【问题标题】:Prepend lines to file in Java在 Java 中将行添加到文件中
【发布时间】:2010-03-29 12:51:13
【问题描述】:

有没有办法在 Java 文件中添加一行,而无需创建临时文件并将所需内容写入其中?

【问题讨论】:

    标签: java file-io


    【解决方案1】:

    不,没有办法在 Java 中安全做到这一点。 (或 AFAIK,任何其他编程语言。)

    没有任何主流操作系统中的文件系统实现支持这种东西,而且你不会发现任何主流编程语言都支持这种特性。

    现实世界的文件系统是在将数据存储为固定大小的“块”的设备上实现的。不可能实现一个文件系统模型,您可以将字节插入文件中间而不显着减慢文件 I/O、浪费磁盘空间或两者兼而有之。


    涉及文件就地重写的解决方案本质上是不安全的。如果您的应用程序在 prepend / rewrite 过程中被终止或电源中断,您可能会丢失数据。我不建议在实践中使用这种方法。

    使用临时文件并重命名。更安全。

    【讨论】:

    • 据说是不安全的(依赖于操作系统/文件系统/设备),但是使用内存映射的方法,由于文件的一部分可以像字节数组一样被修改,就地替换可以做完了。但这也仅限于“替换”字节,而不是“前置/插入”额外字节。
    • 正确。但是这个问题明确地是关于 prepending 一行到文件。这就是我的答案所要解决的问题。
    【解决方案2】:

    有一种方法,它涉及重写整个文件(但没有临时文件)。正如其他人提到的,没有文件系统支持将内容添加到文件中。下面是一些示例代码,它使用 RandomAccessFile 写入和读取内容,同时将一些内容缓冲在内存中:

    public static void main(final String args[]) throws Exception {
        File f = File.createTempFile(Main.class.getName(), "tmp");
        f.deleteOnExit();
    
        System.out.println(f.getPath());
    
        // put some dummy content into our file
        BufferedWriter w = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f)));
        for (int i = 0; i < 1000; i++) {
            w.write(UUID.randomUUID().toString());
            w.write('\n');
        }
        w.flush();
        w.close();
    
                // append "some uuids" to our file
        int bufLength = 4096;
        byte[] appendBuf = "some uuids\n".getBytes();
        byte[] writeBuf = appendBuf;
        byte[] readBuf = new byte[bufLength];
    
        int writeBytes = writeBuf.length;
    
        RandomAccessFile rw = new RandomAccessFile(f, "rw");
        int read = 0;
        int write = 0;
    
        while (true) {
                        // seek to read position and read content into read buffer
            rw.seek(read);
            int bytesRead = rw.read(readBuf, 0, readBuf.length);
    
                        // seek to write position and write content from write buffer
            rw.seek(write);
            rw.write(writeBuf, 0, writeBytes);
    
                        // no bytes read - end of file reached
            if (bytesRead < 0) {
                                // end of
                break;
            }
    
                        // update seek positions for write and read
            read += bytesRead;
            write += writeBytes;
            writeBytes = bytesRead;
    
                        // reuse buffer, create new one to replace (short) append buf
            byte[] nextWrite = writeBuf == appendBuf ? new byte[bufLength] : writeBuf;
            writeBuf = readBuf;
            readBuf = nextWrite;
        };
    
        rw.close();
    
                // now show the content of our file
        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(f)));
    
        String line;
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
        }
    }
    

    【讨论】:

      【解决方案3】:

      没有。没有“文件内移位”操作,只有离散大小的读写。

      【讨论】:

        【解决方案4】:

        可以通过读取与您要添加的内容长度相等的文件块,写入新内容来代替它,读取后面的块并将其替换为您之前读取的内容,以及以此类推,一直到文件末尾。

        但是,不要那样做,因为如果在该过程的中间有任何事情停止(内存不足、断电、恶意线程调用System.exit),数据将会丢失。请改用临时文件。

        【讨论】:

          【解决方案5】:

          您可以将文件内容存储在字符串中,并使用 StringBuilder-Object 预先添加所需的行。您只需先放置所需的行,然后附加文件内容字符串。
          不需要额外的临时文件。

          【讨论】:

          • 这会将现有文件内容替换为新内容。它不会通过移动文件系统中的内容并将新内容放在它之前来更改文件,这是问题所要求的。
          【解决方案6】:
          private static void addPreAppnedText(File fileName) {
              FileOutputStream fileOutputStream =null;
          
              BufferedReader br = null;
              FileReader fr = null;
              String newFileName = fileName.getAbsolutePath() + "@";
          
              try {
                  fileOutputStream = new FileOutputStream(newFileName);
                  fileOutputStream.write("preappendTextDataHere".getBytes());
          
                  fr = new FileReader(fileName);
                  br = new BufferedReader(fr);
          
                  String sCurrentLine;
          
                  while ((sCurrentLine = br.readLine()) != null) {
                      fileOutputStream.write(("\n"+sCurrentLine).getBytes());
          
                  }
                  fileOutputStream.flush();
              } catch (IOException e) {
                  e.printStackTrace();
              } finally {
                  try {
                      fileOutputStream.close();
                      if (br != null)
                          br.close();
          
                      if (fr != null)
                          fr.close();
          
                      new File(newFileName).renameTo(new File(newFileName.replace("@", "")));
                  } catch (IOException ex) {
                      ex.printStackTrace();
                  }
              }
          }
          

          【讨论】:

          • 仅代码回答。它创建了第二个文件,所以它没有做 OP 想要的。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-09-13
          • 2014-04-13
          • 2013-02-19
          • 1970-01-01
          • 1970-01-01
          • 2012-04-06
          • 2016-02-08
          相关资源
          最近更新 更多