在java中编写时限制文件大小

时间:2016-08-23 05:13:57

标签: java file bufferedwriter

我需要将文件大小限制为1 GB,最好使用BufferedWriter

是否可以使用BufferedWriter或者我必须使用其他库?

try (BufferedWriter writer = Files.newBufferedWriter(path)) {   
    //...
    writer.write(lines.stream());
} 

4 个答案:

答案 0 :(得分:9)

您始终可以编写自己的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 :(得分:2)

在写行的情况下,精确到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方式更麻烦。

答案 2 :(得分:0)

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);
    }
}

答案 3 :(得分:-1)

IIUC,有各种方法可以做到。

  1. 继续在chucks中写入数据并将其刷新,并在每次刷新后继续检查文件大小。
  2. 使用log4j(或某些日志框架),它可以让我们在特定大小或时间或其他触发点之后翻转到新文件。
  3. 虽然BufferedReader很棒,但java中有一些新的API可以让它更快。 Fastest way to write huge data in text file Java