0

I have the following script to create 3 files:

set serveroutput on

declare
  nombreArchivo             varchar2(30);
  f_out                     UTL_FILE.FILE_TYPE;
begin
  nombreArchivo :='fich_fseek.txt';
  dbms_output.put_line('Abrir el fichero '||nombrearchivo||' en modo escritura.');
  f_out:=UTL_FILE.FOPEN('TEMPORAL',nombreArchivo,'w');
  UTL_FILE.PUT_LINE(f_out,'Hola, me llamo Álvaro.');
  UTL_FILE.PUT_LINE(f_out,'Esto es una prueba para ver cómo funcionan las funciones FSEEK y FGETPOS.');  
  UTL_FILE.PUT_LINE(f_out,'Espero que te diviertas.');
  UTL_FILE.NEW_LINE(f_out,1);
  UTL_FILE.PUT_LINE(f_out,'Atentamente,');
  UTL_FILE.PUT_LINE(f_out,'el que esto escribe'); 
  UTL_FILE.FCLOSE(f_out);

  nombreArchivo :='caracter.txt';
  dbms_output.put_line('Abrir el fichero '||nombrearchivo||' en modo escritura.');
  f_out:=UTL_FILE.FOPEN('TEMPORAL',nombreArchivo,'w');
  UTL_FILE.PUT(f_out,'a');
  UTL_FILE.FCLOSE(f_out);

  nombreArchivo :='vacio.txt';
  dbms_output.put_line('Abrir el fichero '||nombrearchivo||' en modo escritura.');
  f_out:=UTL_FILE.FOPEN('TEMPORAL',nombreArchivo,'w');
  UTL_FILE.FCLOSE(f_out);
exception
  when others then -- así me aseguro que cualquier flujo abierto será cerrado
    dbms_output.put_line('Se ha producido un error: '||SQLERRM);
    UTL_FILE.FCLOSE_ALL;
end;
/

the problem arises when I create another script to read the files without making use of the exception clause :

set serveroutput on

declare
  nombreArchivo             varchar2(30):='fich_fseek.txt';
  --nombreArchivo             varchar2(30):='caracter.txt';
  --nombreArchivo             varchar2(30):='vacio.txt';
  f_out                     UTL_FILE.FILE_TYPE;
  texto                     varchar2(100);
  posición                  pls_integer := 0;

  existe                    boolean;
  tamaño_archivo            number;
  tamaño_bloque             number; 
begin
  UTL_FILE.FGETATTR('TEMPORAL', nombreArchivo, existe, tamaño_archivo, tamaño_bloque);
  if existe then
    if tamaño_archivo > 0 then
      dbms_output.put_line('Abrir el fichero '||nombrearchivo||' en modo lectura, que tiene un tamaño de '||tamaño_archivo||' bytes.');
      f_out:=UTL_FILE.FOPEN('TEMPORAL',nombreArchivo,'r');

      posición := UTL_FILE.FGETPOS(f_out);
      while posición < tamaño_archivo loop
        UTL_FILE.GET_LINE(f_out, texto);
        dbms_output.put_line('pre  Posición '||posición);
        dbms_output.put_line(texto);
        posición := UTL_FILE.FGETPOS(f_out);
        dbms_output.put_line('post Posición '||posición);
      end loop;

      UTL_FILE.FCLOSE(f_out);
    else
      dbms_output.put_line('El fichero '||nombrearchivo||' está vacío (0 bytes).');
    end if;
  else
    dbms_output.put_line('El archivo '||nombrearchivo||' no existe');
  end if;
end;
/

Then an ORA-01403 "no data found" happens, but only with the 'fich_fseek.txt' file.

Nicolás Alarcón Rapela
  • 2,714
  • 1
  • 18
  • 29
Álvaro
  • 1,351
  • 1
  • 10
  • 14
  • Seems to work OK. What character set is your database, and what character encoding does the text file get? I suspect you have a difference between character count and byte count, though I can't break it at the moment. Which line is the error coming from? – Alex Poole May 20 '15 at 09:55
  • The error report is: ORA-01403: No se ha encontrado ningún dato ORA-06512: en "SYS.UTL_FILE", línea 98 ORA-06512: en "SYS.UTL_FILE", línea 656 ORA-06512: en línea 23 01403. 00000 - "no data found". How can I look for the character set? – Álvaro May 20 '15 at 10:16
  • Anyway, after reading the last line FGETPOS should indicate position 163 (out of the 164 the whole file has), not 158 – Álvaro May 20 '15 at 10:28
  • Where can I get more info about bug 8851175? Google doesn't give any good answer – Álvaro May 20 '15 at 10:30
  • Yes, I'm using in on Windows, so the end of line will be coded with 2 characteres (158 linux characters + 6 extra on windows as there are six lines = 164) – Álvaro May 20 '15 at 10:37
  • The 1403 basically means it's reading past the end of the file somehow, I think. Not sure how quite though, sorry. The bug was someone seeing this but no details or explanation. You haven't show the output you get though; particularly what `tamaño_archivo` you get, and the last `posición`. Presumably you have a mismatch there. The 158 vs 164 suggests it's confused, about line endings perhaps. – Alex Poole May 20 '15 at 10:41
  • The output is: Abrir el fichero fich_fseek.txt en modo lectura, que tiene un tamaño de 164 bytes. pre Posición 0 Hola, me llamo Álvaro. post Posición 24 pre Posición 24 Esto es una prueba para ver cómo funcionan las funciones FSEEK y FGETPOS. post Posición 99 pre Posición 99 Espero que te diviertas. post Posición 124 pre Posición 124 post Posición 125 pre Posición 125 Atentamente, post Posición 138 pre Posición 138 el que esto escribe post Posición 158 – Álvaro May 20 '15 at 10:44
  • Right, so those reported positions are apparently counted using one line ending, just CR, while the character count is using CRLF. Which is odd, they should both be in bytes, so the same. It's reading past the end of the file because of that count discrepancy. Unfortunately I don't know how to avoid that off-hand. – Alex Poole May 20 '15 at 10:54

1 Answers1

0

Thanks to Alex Poole for his comments. In effect, if in Windows is counting the new line characters in a wrong way, then instead of reading until readed_bytes is less than the file_size I will use a corrected_size: loop until readed_bytes is less than the corrected_size. And the correction is quite simple, at the starting point corrected_size equals file_size, but every time a new line is read the corrected_size will decrease in one unit (byte):

set serveroutput on

declare
  nombreArchivo             varchar2(30):='fich_fseek.txt';
  --nombreArchivo             varchar2(30):='caracter.txt';
  --nombreArchivo             varchar2(30):='vacio.txt';
  f_out                     UTL_FILE.FILE_TYPE;
  texto                     varchar2(100);
  posición                  pls_integer := 0;

  existe                    boolean;
  tamaño_archivo            number;
  tamaño_bloque             number;
  tamaño_corregido          number;
begin
  UTL_FILE.FGETATTR('TEMPORAL', nombreArchivo, existe, tamaño_archivo, tamaño_bloque);
  if existe then
    if tamaño_archivo > 0 then
      dbms_output.put_line('Abrir el fichero '||nombrearchivo||' en modo lectura, que tiene un tamaño de '||tamaño_archivo||' bytes.');
      f_out:=UTL_FILE.FOPEN('TEMPORAL',nombreArchivo,'r');

      posición := UTL_FILE.FGETPOS(f_out);
      tamaño_corregido := tamaño_archivo;
      while posición < tamaño_corregido loop -- hay que poner el -6  para evitar un error no_data_found
        UTL_FILE.GET_LINE(f_out, texto);
        --dbms_output.put_line('pre  Posición '||posición);
        dbms_output.put_line(texto);
        posición := UTL_FILE.FGETPOS(f_out);
        --dbms_output.put_line('post Posición '||posición);
        tamaño_corregido := tamaño_corregido-1;
      end loop;

      UTL_FILE.FCLOSE(f_out);
    else
      dbms_output.put_line('El fichero '||nombrearchivo||' está vacío (0 bytes).');
    end if;
  else
    dbms_output.put_line('El archivo '||nombrearchivo||' no existe');
  end if;
end;
/

an alternative version using byte by byte reading:

set serveroutput on

declare
  nombreArchivo             varchar2(30):='fich_fseek.txt';
  --nombreArchivo             varchar2(30):='caracter.txt';
  --nombreArchivo             varchar2(30):='vacio.txt';
  f_out                     UTL_FILE.FILE_TYPE;
  texto                     varchar2(100) := '';
  posición                  pls_integer := 0;

  existe                    boolean;
  tamaño_archivo            number;
  tamaño_bloque             number;

  flag_acento               boolean := false;
  tamaño_corregido          number;
begin
  UTL_FILE.FGETATTR('TEMPORAL', nombreArchivo, existe, tamaño_archivo, tamaño_bloque);
  if existe then
    if tamaño_archivo > 0 then
      dbms_output.put_line('Abrir el fichero '||nombrearchivo||' en modo lectura, que tiene un tamaño de '||tamaño_archivo||' bytes.');
      f_out:=UTL_FILE.FOPEN('TEMPORAL',nombreArchivo,'r');

      posición := UTL_FILE.FGETPOS(f_out);
      tamaño_corregido := tamaño_archivo;
      while posición < tamaño_corregido  loop 
        UTL_FILE.GET_RAW(f_out, texto, 1);
        if texto = 'C3' then
          --dbms_output.put_line('Encontrado');
          flag_acento := true; --TODO
          goto CONTINUE;
        end if;
        if flag_acento then
          dbms_output.put_line('Posición '||rpad(posición,3)||' '||texto||': '||utl_raw.cast_to_varchar2('C3'||texto));
          flag_acento := false;
        else
          dbms_output.put_line('Posición '||rpad(posición,3)||' '||texto||': '||CHR(TO_NUMBER(texto,'xx')));
        end if;

        if texto = '0A' then -- caracter de sálto de línea
          --exit;
          tamaño_corregido := tamaño_corregido-1;
        end if;

        <<CONTINUE>> posición := UTL_FILE.FGETPOS(f_out);
      end loop;
      --dbms_output.put_line('ASDF '||CHR(TO_NUMBER('C3','xx'))||CHR(TO_NUMBER('81','xx')));
      /*unión := utl_raw.cast_to_varchar2('C381');
      dbms_output.put_line('ASDF '||unión );*/
      UTL_FILE.FCLOSE(f_out);
    else
      dbms_output.put_line('El fichero '||nombrearchivo||' está vacío (0 bytes).');
    end if;
  else
    dbms_output.put_line('El archivo '||nombrearchivo||' no existe');
  end if;
end;
/
Álvaro
  • 1,351
  • 1
  • 10
  • 14