在 Java 中修改 .txt 文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/822150/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Modify a .txt file in Java
提问by Zakir Hemraj
I have a text file that I want to edit using Java. It has many thousands of lines. I basically want to iterate through the lines and change/edit/delete some text. This will need to happen quite often.
我有一个要使用 Java 编辑的文本文件。它有数千行。我基本上想遍历这些行并更改/编辑/删除一些文本。这将需要经常发生。
From the solutions I saw on other sites, the general approach seems to be:
从我在其他网站上看到的解决方案来看,一般的方法似乎是:
- Open the existing file using a BufferedReader
- Read each line, make modifications to each line, and add it to a StringBuilder
- Once all the text has been read and modified, write the contents of the StringBuilder to a new file
- Replace the old file with the new file
- 使用 BufferedReader 打开现有文件
- 读取每一行,对每一行进行修改,并将其添加到 StringBuilder
- 读取并修改所有文本后,将 StringBuilder 的内容写入新文件
- 用新文件替换旧文件
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?
有人知道更好的解决方案吗?
采纳答案by Andrei Krotkov
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.
如果您对文件系统具有修改权限,则您可能还具有删除和重命名权限。
回答by Paul Sonier
If the file is large, you might want to use a FileStream for output, but that seems pretty much like it is the simplest process to do what you're asking (and without more specificity i.e. on what types of changes / edits / deletions you're trying to do, it's impossible to determine what more complicated way might work).
如果文件很大,您可能希望使用 FileStream 进行输出,但这似乎是执行您要求的最简单的过程(并且没有更具体的内容,即您对哪些类型的更改/编辑/删除'正在尝试做,不可能确定哪种更复杂的方法可能有效)。
回答by lumpynose
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.
通常,您不能就地编辑文件;它只是一个很长的字符序列,恰好包含换行符。如果您的更改不会更改每行中的字符数,则可以就地编辑。
回答by Will Hartung
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.
从根本上说,您不必重新创建文件批发,特别是如果它只是一个文本文件。
回答by James Van Huis
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.
如果文件包含名称/值对(或类似的),那么您可能会使用Properties,或者使用平面文件 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.
或者,您是否考虑过不经常写入数据?对文件的内存副本进行操作应该相对简单。如果没有需要实时更新文件的外部资源,那么每次要进行修改时都不需要去磁盘。如果您担心数据备份,您可以运行计划任务将定期更新写入磁盘。
回答by Peter Lawrey
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.
如果文件只有几千行,您应该能够一次读取整个文件并将其转换为字符串。
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) {
}
}
回答by Valentin Rocher
Can't you use regular expressions, if you know what you want to change ? Jakarta Regexpshould probably do the trick.
如果您知道要更改的内容,就不能使用正则表达式吗?Jakarta Regexp应该可以解决问题。
回答by Tamas Rev
I think, FileOutputStream.getFileChannel()
will help a lot, see FileChannel api
http://java.sun.com/javase/6/docs/api/java/nio/channels/FileChannel.html
我认为,FileOutputStream.getFileChannel()
会有很大帮助,请参阅 FileChannel api
http://java.sun.com/javase/6/docs/api/java/nio/channels/FileChannel.html
回答by artaxerxe
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. But this, only if you need to have a good performance!You would need to get a FileChannel
via a RandomAccessFile
, like this:
虽然这个问题是很久以前发布的,但我认为把我的答案放在这里很好。我认为最好的方法是在这种情况下使用FileChannel
from java.nio.channels
package。但这,只有当你需要有一个好的表现!您需要FileChannel
通过 a获得一个RandomAccessFile
,如下所示:
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!
希望我的回答能帮到你!
回答by sendon1982
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();
}
}
}