Java - 防止 PrintWriter 每次都覆盖整个文件

Java - Prevent PrintWriter to overwrite the entire file everytime

我有一个模拟程序,在执行过程中需要非常频繁地将某些结果写入 csv 文件。我发现 printwriter 有问题,这会大大减慢我的程序 运行,因为输出文件的大小越来越大(接近 100 万行)。我怀疑它每次都从一开始就覆盖整个文件,而每次调用它时我只需要在底部追加一行。下面是写函数相关的代码。

写作功能之一:

    public void printHubSummary(Hub hub, String filePath) {
        
        try {
            StringBuilder sb = new StringBuilder();   
            
            String h = hub.getHub_code();
            String date = Integer.toString(hub.getGs().getDate());
            String time = hub.getGs().getHHMMFromMinute(hub.getGs().getClock());
            String wgt = Double.toString(hub.getIb_wgt());

                    
            sb.append(h+","+date+","+time+","+wgt);
//          System.out.println("truck print line: " + sb);
            FileWriter.writeFile(sb.toString(),filePath);
        }
        
        catch (Exception e) {
            System.out.println("Something wrong when outputing truck summary file!");
            e.printStackTrace();        
        }
    }

文件写入代码:(应该是问题所在!)

    public static boolean writeFile(String newStr, String filename) throws IOException {
    boolean flag = false;
    String filein = newStr + "\r\n";
    String temp = "";

    FileInputStream fis = null;
    InputStreamReader isr = null;
    BufferedReader br = null;

    FileOutputStream fos = null;
    PrintWriter pw = null;
    try {
        File file = new File(filename);
        fis = new FileInputStream(file);
        isr = new InputStreamReader(fis);
        br = new BufferedReader(isr);
        StringBuffer buf = new StringBuffer();

        for (int j = 1; (temp = br.readLine()) != null; j++) {
            buf = buf.append(temp);
            buf = buf.append(System.getProperty("line.separator"));
        }
        if (buf.length() > 0 && buf.charAt(0) == '\uFEFF') {
            buf.deleteCharAt(0);
        }
        buf.append(filein);

        fos = new FileOutputStream(file);
        byte[] unicode = {(byte)0xEF, (byte)0xBB, (byte)0xBF};
        fos.write(unicode);
        pw = new PrintWriter(fos);
        
        pw.write(buf.toString().toCharArray());
        pw.flush();
        flag = true;
    } catch (IOException e1) {
        throw e1;
    } finally {
        if (pw != null) {
            pw.close();
        }
        if (fos != null) {
            fos.close();
        }
        if (br != null) {
            br.close();
        }
        if (isr != null) {
            isr.close();
        }
        if (fis != null) {
            fis.close();
        }
    }
    return flag;
}

代码修改更新。我已经冻结了重复覆盖整个文件的操作。它似乎解决了这个问题,但写了一段时间它也变慢了。这是编写非常大的文件的最佳安排吗?还可以进行哪些其他修改以提高效率?

public static boolean writeFile1(String newStr, String filename) throws IOException {
        boolean flag = false;
        String filein = newStr + "\r\n";
        String temp = "";

        FileInputStream fis = null;
        InputStreamReader isr = null;
        BufferedReader br = null;

        FileOutputStream fos = null;
        PrintWriter pw = null;
        try {
            File file = new File(filename);
            fis = new FileInputStream(file);
            isr = new InputStreamReader(fis);
            br = new BufferedReader(isr);
            StringBuffer buf = new StringBuffer();

//          for (int j = 1; (temp = br.readLine()) != null; j++) {
//              buf = buf.append(temp);
//              buf = buf.append(System.getProperty("line.separator"));
//          }
//          if (buf.length() > 0 && buf.charAt(0) == '\uFEFF') {
//              buf.deleteCharAt(0);
//          }
            buf.append(filein);

            fos = new FileOutputStream(file,true);
            byte[] unicode = {(byte)0xEF, (byte)0xBB, (byte)0xBF};
            fos.write(unicode);
            pw = new PrintWriter(fos);
            
            pw.write(buf.toString().toCharArray());
            pw.flush();
            flag = true;
        } catch (IOException e1) {
            throw e1;
        } finally {
            if (pw != null) {
                pw.close();
            }
            if (fos != null) {
                fos.close();
            }
            if (br != null) {
                br.close();
            }
            if (isr != null) {
                isr.close();
            }
            if (fis != null) {
                fis.close();
            }
        }
        return flag;
    }

FileOutputStream 构造函数提供第二个参数以指定是否使用附加模式,该模式将添加到文件末尾而不是覆盖它。

fos = new FileOutputStream(file, true);

或者,您可以在附加模式下创建单个静态 PrintWriter,这可能会更快,因为它减少了垃圾回收。

使用更丰富的文件/路径/Java NIO2:下面的代码至少需要Java 7。

Path path = Paths.get(filename);
try (BufferedWriter bw = Files.newBufferedWriter(
      path, StandardCharsets.UTF_8, StandardOpenOption.APPEND, StandardOpenOption.CREATE, StandardOpenOption.WRITE)) {
  bw.append(filein);
  bw.newLine();
}

这里的提示是 StandardOpenOption

您可能需要在之前编写一些额外的代码来编写 Unicode 部分(并修复 StandardCharsets.UTF_8):

if (Files.notExists(path)) {
  Files.write(path, new byte[] {(byte)0xEF, (byte)0xBB, (byte)0xBF});
}

另外,尽量不要在本地方法中使用StringBuffer,使用StringBuilder:大多数时候不需要同步。