写入 java 时限制文件大小
Limit file size while writing in java
我需要将文件大小限制为 1 GB,同时最好使用 BufferedWriter
。
是否可以使用 BufferedWriter
或者我必须使用其他库?
喜欢
try (BufferedWriter writer = Files.newBufferedWriter(path)) {
//...
writer.write(lines.stream());
}
IIUC,方法多种多样
- 继续在卡盘中写入数据并刷新它,并在每次刷新后继续检查文件大小。
- 使用 log4j(或某些日志记录框架),它可以让我们在特定大小、时间或其他触发点后滚动到新文件。
- 虽然 BufferedReader 很棒,但 java 中有一些新的 API 可以使其更快。 Fastest way to write huge data in text file Java
您可以随时编写自己的 OutputStream
来限制写入的 字节 的数量。
以下假定您希望在超出大小时抛出异常。
public final class LimitedOutputStream extends FilterOutputStream {
private final long maxBytes;
private long bytesWritten;
public LimitedOutputStream(OutputStream out, long maxBytes) {
super(out);
this.maxBytes = maxBytes;
}
@Override
public void write(int b) throws IOException {
ensureCapacity(1);
super.write(b);
}
@Override
public void write(byte[] b) throws IOException {
ensureCapacity(b.length);
super.write(b);
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
ensureCapacity(len);
super.write(b, off, len);
}
private void ensureCapacity(int len) throws IOException {
long newBytesWritten = this.bytesWritten + len;
if (newBytesWritten > this.maxBytes)
throw new IOException("File size exceeded: " + newBytesWritten + " > " + this.maxBytes);
this.bytesWritten = newBytesWritten;
}
}
您现在当然必须手动设置 Writer
/OutputStream
链。
final long SIZE_1GB = 1073741824L;
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
new LimitedOutputStream(Files.newOutputStream(path), SIZE_1GB),
StandardCharsets.UTF_8))) {
//
}
在您写行的情况下,将字节精确到 1 GB 是非常困难的。每行可能包含未知数量的字节。我假设您想在文件中逐行写入数据。
但是,您可以在将行写入文件之前检查行有多少字节,另一种方法是在写入每一行后检查文件大小。
下面的基本例子每次写一行。这里 这只是一个测试! 文本以 UTF-8 编码在文件中占用 21 个字节。最终在 49 次写入后达到 1029 字节并停止写入。
public class Test {
private static final int ONE_KB = 1024;
public static void main(String[] args) {
File file = new File("D:/test.txt");
try (BufferedWriter writer = Files.newBufferedWriter(file.toPath())) {
while (file.length() < ONE_KB) {
writer.write("This is just a test !");
writer.flush();
}
System.out.println("1 KB Data is written to the file.!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
如您所见,我们已经超出了 1KB 的限制,因为上面的程序写入了 1029 字节且不少于 1024 字节。
第二种方法是在将字节写入文件之前根据特定编码检查字节。
public class Test {
private static final int ONE_KB = 1024;
public static void main(String[] args) throws UnsupportedEncodingException {
File file = new File("D:/test.txt");
String data = "This is just a test !";
int dataLength = data.getBytes("UTF-8").length;
try (BufferedWriter writer = Files.newBufferedWriter(file.toPath())) {
while (file.length() + dataLength < ONE_KB) {
writer.write(data);
writer.flush();
}
System.out.println("1 KB Data written to the file.!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
在这种方法中,我们在将字节长度写入文件之前检查字节长度。所以,它将写入 1008 字节,然后停止写入。
两种方法都有问题,
- 写入并检查:您可能会得到一些额外的字节,文件大小可能会超过限制
- 检查并写入:如果下一行包含大量数据,您的字节数可能会少于限制。你应该小心编码。
但是,还有其他方法可以使用某些第三方库(例如 apache io 进行此验证,我发现它比传统的 java 方法更麻烦。
int maxSize = 1_000_000_000;
Charset charset = StandardCharsets.UTF_F);
int size = 0;
int lineCount = 0;
while (lineCount < lines.length) {
long size2 = size + (lines[lineCount] + "\r\n").getBytes(charset).length;
if (size2 > maxSize) {
break;
}
size = size2;
++lineCount;
}
List<String> linesToWrite = lines.substring(0, lineCount);
Path path = Paths.get("D:/test.txt");
Files.write(path, linesToWrite , charset);
或仅解码一次时速度更快:
int lineCount = 0;
try (FileChannel channel = new RandomAccessFile("D:/test.txt", "w").getChannel()) {
ByteBuffer buf = channel.map(FileChannel.MapMode.WRITE, 0, maxSize);
lineCount = lines.length;
for (int i = 0; i < lines.length; i++) {
bytes[] line = (lines.get(i) + "\r\n").getBytes(charset);
if (line.length > buffer.remaining()) {
lineCount = i;
break;
}
buffer.put(line);
}
}
我需要将文件大小限制为 1 GB,同时最好使用 BufferedWriter
。
是否可以使用 BufferedWriter
或者我必须使用其他库?
喜欢
try (BufferedWriter writer = Files.newBufferedWriter(path)) {
//...
writer.write(lines.stream());
}
IIUC,方法多种多样
- 继续在卡盘中写入数据并刷新它,并在每次刷新后继续检查文件大小。
- 使用 log4j(或某些日志记录框架),它可以让我们在特定大小、时间或其他触发点后滚动到新文件。
- 虽然 BufferedReader 很棒,但 java 中有一些新的 API 可以使其更快。 Fastest way to write huge data in text file Java
您可以随时编写自己的 OutputStream
来限制写入的 字节 的数量。
以下假定您希望在超出大小时抛出异常。
public final class LimitedOutputStream extends FilterOutputStream {
private final long maxBytes;
private long bytesWritten;
public LimitedOutputStream(OutputStream out, long maxBytes) {
super(out);
this.maxBytes = maxBytes;
}
@Override
public void write(int b) throws IOException {
ensureCapacity(1);
super.write(b);
}
@Override
public void write(byte[] b) throws IOException {
ensureCapacity(b.length);
super.write(b);
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
ensureCapacity(len);
super.write(b, off, len);
}
private void ensureCapacity(int len) throws IOException {
long newBytesWritten = this.bytesWritten + len;
if (newBytesWritten > this.maxBytes)
throw new IOException("File size exceeded: " + newBytesWritten + " > " + this.maxBytes);
this.bytesWritten = newBytesWritten;
}
}
您现在当然必须手动设置 Writer
/OutputStream
链。
final long SIZE_1GB = 1073741824L;
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
new LimitedOutputStream(Files.newOutputStream(path), SIZE_1GB),
StandardCharsets.UTF_8))) {
//
}
在您写行的情况下,将字节精确到 1 GB 是非常困难的。每行可能包含未知数量的字节。我假设您想在文件中逐行写入数据。
但是,您可以在将行写入文件之前检查行有多少字节,另一种方法是在写入每一行后检查文件大小。
下面的基本例子每次写一行。这里 这只是一个测试! 文本以 UTF-8 编码在文件中占用 21 个字节。最终在 49 次写入后达到 1029 字节并停止写入。
public class Test {
private static final int ONE_KB = 1024;
public static void main(String[] args) {
File file = new File("D:/test.txt");
try (BufferedWriter writer = Files.newBufferedWriter(file.toPath())) {
while (file.length() < ONE_KB) {
writer.write("This is just a test !");
writer.flush();
}
System.out.println("1 KB Data is written to the file.!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
如您所见,我们已经超出了 1KB 的限制,因为上面的程序写入了 1029 字节且不少于 1024 字节。
第二种方法是在将字节写入文件之前根据特定编码检查字节。
public class Test {
private static final int ONE_KB = 1024;
public static void main(String[] args) throws UnsupportedEncodingException {
File file = new File("D:/test.txt");
String data = "This is just a test !";
int dataLength = data.getBytes("UTF-8").length;
try (BufferedWriter writer = Files.newBufferedWriter(file.toPath())) {
while (file.length() + dataLength < ONE_KB) {
writer.write(data);
writer.flush();
}
System.out.println("1 KB Data written to the file.!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
在这种方法中,我们在将字节长度写入文件之前检查字节长度。所以,它将写入 1008 字节,然后停止写入。
两种方法都有问题,
- 写入并检查:您可能会得到一些额外的字节,文件大小可能会超过限制
- 检查并写入:如果下一行包含大量数据,您的字节数可能会少于限制。你应该小心编码。
但是,还有其他方法可以使用某些第三方库(例如 apache io 进行此验证,我发现它比传统的 java 方法更麻烦。
int maxSize = 1_000_000_000;
Charset charset = StandardCharsets.UTF_F);
int size = 0;
int lineCount = 0;
while (lineCount < lines.length) {
long size2 = size + (lines[lineCount] + "\r\n").getBytes(charset).length;
if (size2 > maxSize) {
break;
}
size = size2;
++lineCount;
}
List<String> linesToWrite = lines.substring(0, lineCount);
Path path = Paths.get("D:/test.txt");
Files.write(path, linesToWrite , charset);
或仅解码一次时速度更快:
int lineCount = 0;
try (FileChannel channel = new RandomAccessFile("D:/test.txt", "w").getChannel()) {
ByteBuffer buf = channel.map(FileChannel.MapMode.WRITE, 0, maxSize);
lineCount = lines.length;
for (int i = 0; i < lines.length; i++) {
bytes[] line = (lines.get(i) + "\r\n").getBytes(charset);
if (line.length > buffer.remaining()) {
lineCount = i;
break;
}
buffer.put(line);
}
}