在编写过程中,java.io.BufferedWriter会节流或完全停止,有人知道原因吗?
如问题中所述,在使用在编写过程中,java.io.BufferedWriter会节流或完全停止,有人知道原因吗?,java,intellij-idea,io,Java,Intellij Idea,Io,如问题中所述,在使用java.io.BufferedWriter进行写入时,我遇到了奇怪的写入速度限制(甚至完全暂停) 我的程序试图从一堆.csv文件中读取数据,然后将它们重新打包到按第一列分组的另一堆.csv文件中 例如,如果.csv文件Tom,86,87,88中有一行,这一行将写入名为Tom.csv的.csv文件中 我使用HashMap缓存写入程序,这样程序只需打开/关闭写入程序一次 (我故意将文件列表和流程逻辑拆分以进行调试) 守则: package dev.repackcsv; imp
java.io.BufferedWriter
进行写入时,我遇到了奇怪的写入速度限制(甚至完全暂停)
我的程序试图从一堆.csv文件中读取数据,然后将它们重新打包到按第一列分组的另一堆.csv文件中
例如,如果.csv文件Tom,86,87,88
中有一行,这一行将写入名为Tom.csv
的.csv文件中
我使用HashMap
缓存写入程序,这样程序只需打开/关闭写入程序一次
(我故意将文件列表和流程逻辑拆分以进行调试)
守则:
package dev.repackcsv;
import java.io.*;
import java.nio.file.*;
import java.util.*;
public class Main {
private static final Path USER_DIR;
private static final Path PROP_FILE;
private static final Properties PROPERTIES;
private static final Path SCAN_DIR;
private static final Path OUTPUT_DIR;
private static final List<Path> SCANNED_FILE_LIST;
private static final Map<String, BufferedWriter> OUTPUT_FILE_MAP;
private static void loadProperties() {
try (InputStream propFileInputStream = Files.newInputStream(PROP_FILE)) {
PROPERTIES.load(propFileInputStream);
} catch (IOException e) {
System.err.println("[Error] Failed to load properties from \"application.properties\"");
System.exit(1);
}
}
private static String getProperty(String propertyName) {
String property = PROPERTIES.getProperty(propertyName);
if (property == null) {
System.err.println("[Error] Undefined property: " + propertyName);
System.exit(1);
}
return property;
}
static {
USER_DIR = Paths.get(System.getProperty("user.dir"));
PROP_FILE = USER_DIR.resolve("application.properties");
if (!Files.exists(PROP_FILE)) {
System.err.println("[Error] \"application.properties\" file does not exist.");
System.exit(1);
}
PROPERTIES = new Properties();
loadProperties();
SCAN_DIR = Paths.get(getProperty("scan.dir")).toAbsolutePath();
if (!Files.exists(SCAN_DIR)) {
System.err.println("[Error] Scan directory does not exist");
System.exit(1);
}
OUTPUT_DIR = Paths.get(getProperty("output.dir")).toAbsolutePath();
if (!Files.exists(OUTPUT_DIR)) {
System.err.println("[Error] Output directory does not exist");
System.exit(1);
}
SCANNED_FILE_LIST = new LinkedList<>();
OUTPUT_FILE_MAP = new HashMap<>();
}
private static void loadScannedFileList()
throws IOException {
try (DirectoryStream<Path> ds = Files.newDirectoryStream(SCAN_DIR)) {
for (Path path : ds) {
SCANNED_FILE_LIST.add(path.toAbsolutePath());
}
}
}
private static BufferedWriter getOutputFileBufferedWriter(String key, String headLine) throws IOException {
if (OUTPUT_FILE_MAP.containsKey(key)) {
return OUTPUT_FILE_MAP.get(key);
} else {
Path outputFile = OUTPUT_DIR.resolve(key + ".csv");
boolean isNewFile = false;
if (!Files.exists(outputFile)) {
Files.createFile(outputFile);
isNewFile = true;
}
BufferedWriter bw = Files.newBufferedWriter(outputFile);
if (isNewFile) {
bw.write(headLine);
bw.newLine();
bw.flush();
}
OUTPUT_FILE_MAP.put(key, bw);
return bw;
}
}
private static void processScannedCSV(Path csvFile)
throws IOException {
System.out.printf("[Info] Current file \"%s\"%n", csvFile);
long fileSize = Files.size(csvFile);
try (BufferedReader br = new BufferedReader(new InputStreamReader(Files.newInputStream(csvFile)))) {
String headLine = br.readLine();
if (headLine == null) { return; }
String dataLine;
long readByteSize = 0;
while ((dataLine = br.readLine()) != null) {
int firstCommaIndex = dataLine.indexOf(',');
if (firstCommaIndex == -1) { continue; }
BufferedWriter bw = getOutputFileBufferedWriter(dataLine.substring(0, firstCommaIndex), headLine);
bw.write(dataLine);
bw.newLine();
readByteSize += dataLine.getBytes().length;
System.out.print("\r[Progress] " + readByteSize + '/' + fileSize);
}
}
System.out.print("\r");
}
private static void processScannedFiles()
throws IOException {
for (Path file : SCANNED_FILE_LIST) {
if (!Files.exists(file)) {
System.out.printf("[WARN] Scanned file \"%s\" does not exist, skipping...%n", file);
continue;
}
if (!file.toString().endsWith(".csv")) { continue; }
processScannedCSV(file);
}
}
public static void main(String[] args)
throws IOException {
loadScannedFileList();
processScannedFiles();
for (BufferedWriter bw : OUTPUT_FILE_MAP.values()) {
bw.flush();
bw.close();
}
}
}
如果有人知道原因/有解决方案,那就太好了:(
谢谢!打开许多文件对磁盘操作系统来说可能是一个沉重的负担,文件句柄的数量(有限!)和“移动写入头”应该可以同时执行 关于
静态s
代码显示了经验(同样与Java有关),可能也来自C语言。因为使用static
是不寻常的。您可以在main
中执行new main().executeMyThings();
并将static
放到其他地方
要采取的措施
- 不要使用文本而是二进制数据,
不要使用编写器/读取器,而要使用
。这会阻止Unicode的来回转换。在Linux上运行Windows UTF-8文件时,还可能会丢失数据输出流/输入流
- 使用
而不是ArrayList
,因为对于许多项目,它可能表现得更好LinkedList
- 您可能希望收集文件路径,而不是BufferedWriter。每个BufferedWriter不仅是一个操作系统资源,而且维护一个缓冲区(内存)。它甚至可能更高效,可以写入头行,在追加模式下关闭并重新打开它。标题可以使用
文件写入。writeString
- System.out的成本很高。控制台记录器可能更安全,使用并发会更安全, 但成本也很高
- readByteSize忽略换行符,对于Windows文件为2
- 可以使用较大/较小的缓冲区大小创建BufferedWriter
for (Path path : ds) { SCANNED_FILE_LIST.add(path.toAbsolutePath()); }
ds.forEach(path -> SCANNED_FILE_LIST.add(path.toAbsolutePath());
ds.forEach(path -> SCANNED_FILE_LIST.add(path.toAbsolutePath());