środa, 18 kwietnia 2012

Java FileWriter RandomAccessFile Update

Tytuł jest taki a nie inny, żeby się ładnie w wyszukiwarce znajdowało ;]
generalnie chodzi o to, ze java ma wiele metod dodawania czegos na koniec pliku,
natomiast nie jest już tak różowo, jak trzeba coś zmienić w środku...
Poniżej przykład loga, w którym zmieniać się będzie 1 int, aczkolwiek ta konstrukcja pozwala już na zbudowanie dokładnie wszystkiego.

edit: tak swoja droga, to do zabaw z plikami o wiele lepszy jest linux'owy SED czy AWK, no ale cóż. Może innym razem będzie mi się chciało jakiś fajny skrypt zamieścić. Zresztą czasem trzeba to zrobić w javie, bo tak ci na gorze każą ;]

tak, żeby być fajnym, to wrzuciłem jeszcze enuma ze sztryngami
StringEnum.java
package stringi;

public enum StringEnum {
  HEADER     ("General Log HEADER"), 
  ROW_1     ("jakis tekst, row1:"), 
  ROW_2     ("siakis int:");
  
  private String description;
  
  private StringEnum(String s) {
   description = s;
  }
  
  public String getDescription() {
    return description;
  }
}

a teraz, po tym przydługim wstępie - rozwiązanie problemu - RandomAccessFile.
Klasa ta pozwala ustawić "kursor" (metoda seek) w dowolnym miejscu dokumentu i potem wpisać żądaną treść (ja akurat używam writeBytes, ale jest tez wiele innych "write'ów")
uwaga: write nie dopisuje treści w danym miejscu przesuwając resztę dalej (jak w wordzie ;]). nie ma tak dobrze. write nadpisuje kolejne bajty do znaku końca linii (tak to z doświadczenia u mnie wyszło)
najłatwiej jest oczywiście nadpisać cały plik od początku, szczególnie, że wtedy odpada problem z ustawianiem długości pliku[setLength()] (tak, żeby ko na końcu nie obcięło, jeśli dodamy coś w środku)

NewTestRandomAccessFile.java
package stringi;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

public class NewTestRandomAccessFile {
    private File file = null;
 private RandomAccessFile generalFileWriter = null;
 private Integer siakisInt = 0;
 
 public NewTestRandomAccessFile(String fileName) {
  try {
   initGeneralLog(fileName);
  } catch (IOException e) {
   e.printStackTrace();
  }
 }
    
 private void initGeneralLog(String fileName) throws IOException{
  file = new File(fileName);
  if(file.exists()){
   file.delete();
   file.createNewFile();
  }
  generalFileWriter = new RandomAccessFile(file, "rw");
  generalFileWriter.writeBytes(buildGeneralLog());
 }

 private String buildGeneralLog(){
  StringBuilder sb = new StringBuilder();
  sb.append(StringEnum.HEADER.getDescription())           .append("\n");
  sb.append(StringEnum.ROW_1.getDescription())  .append("some static data bla bla") .append("\n");
  sb.append(StringEnum.ROW_2.getDescription())  .append(siakisInt +=150)    .append("\n");
  return sb.toString();
 }
 
 
 private void writeDataToGeneralLog(String output) throws IOException {
  generalFileWriter.setLength(output.getBytes().length);
  generalFileWriter.seek(0);
  generalFileWriter.writeBytes(output);
 }
 
 private void closeLog() throws IOException{
  if(generalFileWriter != null){
   writeDataToGeneralLog(buildGeneralLog());
   generalFileWriter.close();
  }
 }
 
 public static void main(String[] args) throws IOException {
  NewTestRandomAccessFile test = new NewTestRandomAccessFile("WrRaThY.txt");
  for(int i = 0; i<10;  i){
   test.writeDataToGeneralLog(test.buildGeneralLog());
  }
  test.closeLog();
  
 }
}

edit:  jest niby jeszcze jeden sposób, żeby updatować plik, ale nie wydaje mi się ani ładny, ani stabilny.
przy dużej ilości zapisów do pliku pewnie się wysypie... ale niech będzie, wrzucę go.

package stringi;

import java.io.FileWriter;
import java.io.IOException;

public class Filewriter {

 /**
  * @param args
  */
 private static FileWriter fw = null;
 private static int samplersProcessedCounter = 0;
 
 public static void main(String[] args) throws IOException, InterruptedException {
     int count = 10;
     Filewriter my = new Filewriter();
     for(int i = 0; i<count;  i){
      my.funkcja();
     }
 }
 
 public void funkcja(){
  try {
   String line = "";

   if (fw == null) {// initiate file writer
    fw = new FileWriter("test.csv");
    line = "col1, col2, col3\n";
    fw.append(line);

   }

   line = "col1row" samplersProcessedCounter ", col2row" samplersProcessedCounter ", col3row" samplersProcessedCounter "\n";
   fw.append(line);
   samplersProcessedCounter  ;
   //WARNING! this is strange, probably will be unstable
   fw.flush();
   fw.close();
   fw=null;
   
  } catch (IOException e) {
   e.printStackTrace();
  }
 }

}

od zwykłego file writera rozni sie tylko miejscem zamykania (stad moje obawy o stabilność, po każdym wierszu trzeba zamknąć plik, znullować referencję i otworzyć plik od nowa...
package stringi;

import java.io.FileWriter;
import java.io.IOException;

public class Filewriter {

 /**
  * @param args
  */
 private static FileWriter fw = null;
 private static int samplersProcessedCounter = 0;
 
 public static void main(String[] args) throws IOException, InterruptedException {
     int count = 10;
     Filewriter my = new Filewriter();
     for(int i = 0; i<count;  i){
      my.funkcja();
     }
     //NORMAL FLUSH AND CLOSE, AFTER EVERYTHING IS DONE
     fw.flush();
     fw.close();
 }
 
 public void funkcja(){
  try {
   String line = "";

   if (fw == null) {// initiate file writer
    fw = new FileWriter("test.csv");
    line = "col1, col2, col3\n";
    fw.append(line);

   }

   line = "col1row" samplersProcessedCounter ", col2row" samplersProcessedCounter ", col3row" samplersProcessedCounter "\n";
   fw.append(line);
   samplersProcessedCounter  ;
   /*WARNING! COMMENT!
   fw.flush();
   fw.close();
   fw=null;*/
   
  } catch (IOException e) {
   e.printStackTrace();
  }
 }

}


Brak komentarzy:

Prześlij komentarz