Оптимизация замены байтов некоторых файлов в Java 8 - PullRequest
2 голосов
/ 04 ноября 2019

У меня есть этот метод в Java, и я хочу улучшить его. Этот метод используется для замены некоторой части (в начале, в середине или в конце) некоторого файла новыми байтами ( выбранная часть может быть заменена меньшим или большим количеством байтов ). Выбор сделан по положению (start) и quantity.

Я не могу использовать внешние библиотеки (guava или другие).

Здесь мой старыйкод:

public static void replaceBytesFile(RandomAccessFile rafTarget,
    byte[] replacers, int start, int quantity) {
  //replaces exact amount of bytes of a file starting at a specified position
  RandomAccessFile rafTemp = null;

  //Ini Select a Random NonExistent File
  File userDirectory = new File(System.getProperty("user.dir"));
  File temporalFile;
  boolean existsTemporalFile = false;
  String temporalFilename = "";
  while (!existsTemporalFile) {
    temporalFilename = "File_" + Double.toString(100000 * Math.random()) + ".tmp";
    temporalFilename = userDirectory + MethodGen.FS + temporalFilename;
    temporalFile = new File(temporalFilename);
    if (!temporalFile.exists()) {
      existsTemporalFile = true;
    }
  }
  //End Select a Random NonExistent File
  try {
    rafTemp = new RandomAccessFile(temporalFilename, "rw");
    int workBufferSize = 65536;
    //Ini Copy first (Start - 1) MethodBytes
    int step = workBufferSize;
    int countPosition = 0;
    while (countPosition < start) {
      rafTarget.seek(countPosition);
      rafTemp.seek(countPosition);
      if ((start - countPosition) < step) {
        step = start - countPosition;
      }
      byte[] WorkBuffer = new byte[step];
      rafTarget.read(WorkBuffer);
      rafTemp.write(WorkBuffer);
      countPosition += step;
    }
    //End Copy first (start - 1) MethodBytes
    rafTemp.write(replacers);
    rafTarget.seek(start + quantity);
    int end = (int) rafTarget.length();
    //Ini Copy last MethodBytes
    step = workBufferSize;
    countPosition = start + quantity;
    while (countPosition < end) {
      rafTarget.seek(countPosition);
      rafTemp.seek(countPosition - quantity + replacers.length);
      if ((end - countPosition) <= step) {
        step = end - countPosition;
      }
      byte[] WorkBuffer = new byte[step];
      rafTarget.read(WorkBuffer);
      rafTemp.write(WorkBuffer);
      countPosition += step;
    }
    //End Copy last MethodBytes

    rafTarget.setLength(0);
    step = workBufferSize;
    countPosition = 0;
    end = (int) rafTemp.length();
    //Ini Copy all MethodBytes to original
    while (countPosition < end) {
      rafTemp.seek(countPosition);
      rafTarget.seek(countPosition);
      if ((end - countPosition) <= step) {
        step = end - countPosition;
      }
      byte[] WorkBuffer = new byte[step];

      rafTemp.read(WorkBuffer);
      rafTarget.write(WorkBuffer);
      countPosition += step;
    }
    //End Copy all MethodBytes to original
    rafTemp.close();
    temporalFile = new File(temporalFilename);
    temporalFile.delete();
  } catch (IOException ioe) {
    System.out.println(ioe.toString());
  } finally {
    try {
      if (rafTemp != null) {
        rafTemp.close();
      }
    } catch (IOException e) {
    }
  }
}

Я копирую вручную из исходного файла во временный файл, в котором выполняются изменения, позже,

Мой код работает, но я хочу узнать лучшую альтернативув Java 8 (предпочтительнее).

Теперь, как проходит тест?

  public static void main(String[] args) {
    String originalFilename = "OriginalTraveling.txt";
    String copiedFilename = "TravelingToBeChanged.txt";

    Path copiedPath = Paths.get(copiedFilename);
    Path originalPath = new File(originalFilename).toPath();
    System.out.println("filename:" + originalFilename);

    String contet = "I want to travel to my Country.";
    try {
      RandomAccessFile raf = new RandomAccessFile(originalFilename, "rw");
      putBytesFile(raf, contet.getBytes(), 0);
      Files.copy(originalPath, copiedPath, StandardCopyOption.REPLACE_EXISTING);
    }
    catch (IOException e) {
      System.out.println("Exception caught " + e.toString());
    }


    try {
      RandomAccessFile raf = new RandomAccessFile(copiedFilename, "rw");
      String toBeChanged = "my Country.";
      String toBeInserted = "India, China, Europe, Latin America, Australia.";
      int position = contet.indexOf(toBeChanged);
      replaceBytesFile(raf, toBeInserted.getBytes(), position, toBeChanged.length());
    }
    catch (IOException e) {
      System.out.println("Exception caught " + e.toString());
    }

    try {
      RandomAccessFile raf = new RandomAccessFile(copiedFilename, "rw");
      String replacedContent = new String(getBytesFile(raf, 0, (int) raf.length()));
      String toBeChanged = "Latin America";
      String toBeInserted = "Colombia";
      int position = replacedContent.indexOf(toBeChanged);
      replaceBytesFile(raf, toBeInserted.getBytes(), position, toBeChanged.length());
    } catch (IOException e) {
      System.out.println("Exception caught " + e.toString());
    }
  }

Метод установки байтов!

  public static void putBytesFile(RandomAccessFile RAFTarget, byte[] content, int position) {
    int size = content.length;
    try {
      long oldPosition = RAFTarget.getFilePointer();
      if (!((position < 0) || !(size > 0))) {
        RAFTarget.seek(position);
        RAFTarget.write(content);
        RAFTarget.seek(oldPosition);
      }
    } catch (java.io.IOException e) {
      System.out.println(e.toString());
    }
  }

Метод Get Files!

  public static byte[] getBytesFile(RandomAccessFile RAFSource, int position, int quantity) {
    byte[] content = null;
    try {
      long oldPosition = RAFSource.getFilePointer();
      if ((position < 0) || !(quantity > 0)) {
        return (content);
      } else {
        if (RAFSource.length() < (position + quantity)) {
          quantity = (int) RAFSource.length() - position;
        }
        RAFSource.seek(position);
        content = new byte[quantity];
        RAFSource.read(content);
        RAFSource.seek(oldPosition);
      }
    } catch (java.io.IOException e) {
      System.out.println(e.toString());
    }
    return content;
  }

Содержимое OriginalTraveling.txt

I want to travel to my Country.

Содержимое TravelingToBeChanged.txt

I want to travel to India, China, Europe, Latin America, Australia.

Наконец, содержимое TravelingToBeChanged.txt

I want to travel to India, China, Europe, Colombia, Australia.

Если это можно заметить, они НЕ меняются на одинаковое количество байтов.

знаете какую-нибудь альтернативу для замены содержимого файла?

1 Ответ

3 голосов
/ 04 ноября 2019

Даже для древнего кода это выглядит ненужным сложным.

Например, вместо

//Ini Select a Random NonExistent File
File userDirectory = new File(System.getProperty("user.dir"));
File temporalFile;
boolean existsTemporalFile = false;
String temporalFilename = "";
while (!existsTemporalFile) {
  temporalFilename = "File_" + Double.toString(100000 * Math.random()) + ".tmp";
  temporalFilename = userDirectory + MethodGen.FS + temporalFilename;
  temporalFile = new File(temporalFilename);
  if (!temporalFile.exists()) {
    existsTemporalFile = true;
  }
}

просто используйте

File temporalFile = File.createTempFile("File_", ".tmp", userDirectory);

См. createTempFile

Далее, вместо

int step = workBufferSize;
int countPosition = 0;
while (countPosition < start) {
  rafTarget.seek(countPosition);
  rafTemp.seek(countPosition);
  if ((start - countPosition) < step) {
    step = start - countPosition;
  }
  byte[] WorkBuffer = new byte[step];
  rafTarget.read(WorkBuffer);
  rafTemp.write(WorkBuffer);
  countPosition += step;
}

Используйте

for(int step=workBufferSize, countPosition=0; countPosition < start; countPosition += step){
  rafTarget.seek(countPosition);
  rafTemp.seek(countPosition);
  if ((start - countPosition) < step) {
    step = start - countPosition;
  }
  byte[] WorkBuffer = new byte[step];
  rafTarget.read(WorkBuffer);
  rafTemp.write(WorkBuffer);
}

Поскольку у вас явно есть начальное утверждение, условие и операция приращения, другими словами,типичная for петля. То же самое относится и к двум другим while циклам.

Однако, с более новыми API, все равно намного проще:

// consider using long for position and Path for the file, unless
// the RandomAccessFile is really needed for other purposes
public static void replaceBytesFile(RandomAccessFile rafTarget,
    byte[] replacers, int start, int quantity) throws IOException {

    // no need to force a particular directory for the temp file
    Path tmp = Files.createTempFile("File_", ".tmp");
    // use import static java.nio.file.StandardOpenOption.*;
    // try( ... ) closes automatically, perfect for a temp file with DELETE_ON_CLOSE
    try(FileChannel tmpCh = FileChannel.open(tmp, READ, WRITE, DELETE_ON_CLOSE)) {
        // closing the target channel would also close rafTarget RandomAccessFile
        FileChannel target = rafTarget.getChannel();
        // just keep the data before start position, only copy remainder
        long retainStart = start + (long)quantity, toCopy = target.size() - retainStart;
        target.transferTo(retainStart, toCopy, tmpCh);
        // write the replacement
        target.write(ByteBuffer.wrap(replacers), start);
        // copy back the remainder, to the new position
        tmpCh.position(0);
        target.transferFrom(tmpCh, start + (long)replacers.length, toCopy);
        // adapt the length if necessary
        target.truncate(start + toCopy + replacers.length);
    }
}
...