简体   繁体   English

修改Java中的a.txt文件

[英]Modify a .txt file in Java

I have a text file that I want to edit using Java. It has many thousands of lines.我有一个文本文件,我想使用 Java 进行编辑。它有数千行。 I basically want to iterate through the lines and change/edit/delete some text.我基本上想遍历这些行并更改/编辑/删除一些文本。 This will need to happen quite often.这需要经常发生。

From the solutions I saw on other sites, the general approach seems to be:从我在其他网站上看到的解决方案来看,一般的做法似乎是:

  • Open the existing file using a BufferedReader使用 BufferedReader 打开现有文件
  • Read each line, make modifications to each line, and add it to a StringBuilder读取每一行,对每一行进行修改,并将其添加到 StringBuilder
  • Once all the text has been read and modified, write the contents of the StringBuilder to a new file读取和修改所有文本后,将 StringBuilder 的内容写入新文件
  • Replace the old file with the new file用新文件替换旧文件

This solution seems slightly "hacky" to me, especially if I have thousands of lines in my text file.这个解决方案对我来说似乎有点“hacky”,尤其是当我的文本文件中有数千行时。

Anybody know of a better solution?有人知道更好的解决方案吗?

I haven't done this in Java recently, but writing an entire file into memory seems like a bad idea. 我最近没有用Java做过这个,但是将整个文件写入内存似乎是一个坏主意。

The best idea that I can come up with is open a temporary file in writing mode at the same time, and for each line, read it, modify if necessary, then write into the temporary file. 我能想到的最好的想法是同时以书写模式打开一个临时文件,对于每一行,读取它,必要时进行修改,然后写入临时文件。 At the end, delete the original and rename the temporary file. 最后,删除原始文件并重命名临时文件。

If you have modify permissions on the file system, you probably also have deleting and renaming permissions. 如果您对文件系统具有修改权限,则可能还具有删除和重命名权限。

if the file is just a few thousand lines you should be able to read the entire file in one read and convert that to a String. 如果文件只有几千行,你应该能够在一次读取中读取整个文件并将其转换为String。

You can use apache IOUtils which has method like the following. 您可以使用具有以下方法的apache IOUtils。

public static String readFile(String filename) throws IOException {
    File file = new File(filename);
    int len = (int) file.length();
    byte[] bytes = new byte[len];
    FileInputStream fis = null;
    try {
        fis = new FileInputStream(file);
        assert len == fis.read(bytes);
    } catch (IOException e) {
        close(fis);
        throw e;
    }
    return new String(bytes, "UTF-8");
}

public static void writeFile(String filename, String text) throws IOException {
    FileOutputStream fos = null;
    try {
        fos = new FileOutputStream(filename);
        fos.write(text.getBytes("UTF-8"));
    } catch (IOException e) {
        close(fos);
        throw e;
    }
}

public static void close(Closeable closeable) {
    try {
        closeable.close();
    } catch(IOException ignored) {
    }
}

如果文件很大,你可能想要使用FileStream进行输出,但这看起来非常像是你所要求的最简单的过程(没有更多的特殊性,即你做什么类型的更改/编辑/删除)我试图做,不可能确定哪种更复杂的方式可行。

No reason to buffer the entire file. 没有理由缓冲整个文件。

Simply write each line as your read it, insert lines when necessary, delete lines when necessary, replace lines when necessary. 只需将每一行写为读取,必要时插入行,必要时删除行,必要时替换行。

Fundamentally, you will not get around having to recreate the file wholesale, especially if it's just a text file. 从根本上说,你不会不得不重新创建批发文件,特别是如果它只是一个文本文件。

What kind of data is it? 它是什么类型的数据? Do you control the format of the file? 你控制文件的格式吗?

If the file contains name/value pairs (or similar), you could have some luck with Properties , or perhaps cobbling together something using a flat file JDBC driver. 如果文件中包含名称/值对(或类似),你可以有一些运气的属性 ,或者使用平面文件JDBC驱动程序也许是拼凑的东西。

Alternatively, have you considered not writing the data so often? 或者,您是否考虑过不经常写数据? Operating on an in-memory copy of your file should be relatively trivial. 在文件的内存中复制操作应该相对简单。 If there are no external resources which need real time updates of the file, then there is no need to go to disk every time you want to make a modification. 如果没有需要实时更新文件的外部资源,则每次要进行修改时都不需要转到磁盘。 You can run a scheduled task to write periodic updates to disk if you are worried about data backup. 如果您担心数据备份,则可以运行计划任务以定期向磁盘写入更新。

Although this question was a time ago posted, I think it is good to put my answer here. 虽然这个问题是在很久以前发布的,但我觉得把答案放在这里是件好事。 I think that the best approach is to use FileChannel from java.nio.channels package in this scenario. 我认为最好的方法是在这种情况下使用java.nio.channels包中的FileChannel But this, only if you need to have a good performance! 但是,这只有你需要有一个良好的表现! You would need to get a FileChannel via a RandomAccessFile , like this: 您需要通过RandomAccessFile获取FileChannel ,如下所示:

java.nio.channels.FileChannel channel = new java.io.RandomAccessFile("/my/fyle/path", "rw").getChannel();

After this, you need a to create a ByteBuffer where you will read from the FileChannel . 在此之后,您需要创建一个ByteBuffer ,您将从FileChannel读取。

this looks something like this: 这看起来像这样:


java.nio.ByteBuffer inBuffer = java.nio.ByteBuffer.allocate(100);
int pos = 0;
int aux = 0;
StringBuilder sb = new StringBuilder();

while (pos != -1) {

    aux = channel.read(inBuffer, pos);
    pos = (aux != -1) ? pos + aux : -1;

    b = inBuffer.array();
    sb.delete(0, sb.length());

    for (int i = 0; i < b.length; ++i) {

         sb.append((char)b[i]);

    }

    //here you can do your stuff on sb

    inBuffer = ByteBuffer.allocate(100);

}

Hope that my answer will help you! 希望我的回答能帮到你!

我认为, FileOutputStream.getFileChannel()会有很多帮助,请参阅FileChannel api http://java.sun.com/javase/6/docs/api/java/nio/channels/FileChannel.html

You can use RandomAccessFile in Java to modify the file on one condition: The size of each line has to be fixed otherwise, when new string is written back, it might override the string in the next line. 您可以在Java中使用RandomAccessFile在一个条件下修改文件:否则必须修复每行的大小,否则,当写回新字符串时,它可能会覆盖下一行中的字符串。

Therefore, in my example, I set the line length as 100 and padding with space string when creating the file and writing back to the file. 因此,在我的示例中,我在创建文件并写回文件时将行长度设置为100并使用空格字符串填充。

So in order to allow update, you need to set the length of line a little larger than the longest length of the line in this file. 因此,为了允许更新,您需要将行的长度设置为略大于此文件中行的最长长度。

public class RandomAccessFileUtil {
public static final long RECORD_LENGTH = 100;
public static final String EMPTY_STRING = " ";
public static final String CRLF = "\n";

public static final String PATHNAME = "/home/mjiang/JM/mahtew.txt";

/**
 *  one two three
    Text to be appended with
    five six seven
    eight nine ten
 * 
 * 
 * @param args
 * @throws IOException
 */
public static void main(String[] args) throws IOException
{
    String starPrefix = "Text to be appended with";
    String replacedString = "new text has been appended";

    RandomAccessFile file = new RandomAccessFile(new File(PATHNAME), "rw");

    String line = "";
    while((line = file.readLine()) != null)
    {
        if(line.startsWith(starPrefix))
        {
            file.seek(file.getFilePointer() - RECORD_LENGTH - 1);
            file.writeBytes(replacedString);
        }

    }
}

public static void createFile() throws IOException
{
    RandomAccessFile file = new RandomAccessFile(new File(PATHNAME), "rw");

    String line1 = "one two three";
    String line2 = "Text to be appended with";
    String line3 = "five six seven";
    String line4 = "eight nine ten";

    file.writeBytes(paddingRight(line1));
    file.writeBytes(CRLF);
    file.writeBytes(paddingRight(line2));
    file.writeBytes(CRLF);
    file.writeBytes(paddingRight(line3));
    file.writeBytes(CRLF);
    file.writeBytes(paddingRight(line4));
    file.writeBytes(CRLF);

    file.close();

    System.out.println(String.format("File is created in [%s]", PATHNAME));
}

public static String paddingRight(String source)
{
    StringBuilder result = new StringBuilder(100);
    if(source != null)
    {
        result.append(source);
        for (int i = 0; i < RECORD_LENGTH - source.length(); i++)
        {
            result.append(EMPTY_STRING);
        }
    }

    return result.toString();
}

} }

In general you cannot edit the file in place; 通常,您无法就地编辑文件; it's simply a very long sequence of characters, which happens to include newline characters. 它只是一个很长的字符序列,恰好包含换行符。 You could edit in place if your changes don't change the number of characters in each line. 如果您的更改未更改每行中的字符数,则可以就地编辑。

Can't you use regular expressions, if you know what you want to change ? 如果您知道要更改的内容,是否可以使用正则表达式? Jakarta Regexp should probably do the trick. Jakarta Regexp应该可以做到这一点。

private static void modifyFile(String filePath, String oldString, String newString) {
    File fileToBeModified = new File(filePath);
    StringBuilder oldContent = new StringBuilder();
    try (BufferedReader reader = new BufferedReader(new FileReader(fileToBeModified))) {
        String line = reader.readLine();
        while (line != null) {
            oldContent.append(line).append(System.lineSeparator());
            line = reader.readLine();
        }
        String content = oldContent.toString();
        String newContent = content.replaceAll(oldString, newString);
        try (FileWriter writer = new FileWriter(fileToBeModified)) {
            writer.write(newContent);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

您可以通过单击“另存为”并保存* .java扩展名保存,将txt文件更改为java。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM