关于IO的一个程序问题,不知道该怎么做 IO 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 写的时候判断。可以参考log4j的实现 先遍历该文件夹下的所有txt文档,将其内容写入一个临时的大的txt文档,然后继续遍历创建文本文档,(每读取1mb的内容就创建一个txt,写入1mb) 抽时间给楼主写了一个demo,给楼主一个编程思路。import java.io.BufferedOutputStream;import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.OutputStreamWriter;import java.io.UnsupportedEncodingException;import java.io.Writer;import java.util.regex.Matcher;import java.util.regex.Pattern;/** * 自定义功能的Writer , 可以随着写入文件的大小切换新文件进行输出。 */public class ShiftWriter extends Writer{ public static final long DEFAUT_MAX_SIZE = 1*1024*1024; public static final String DEFAULT_CHARSET = "GBK"; /** 可计数的输出流 */ static class CounterOutputStream extends OutputStream{ private OutputStream output; private long count=0; public CounterOutputStream(OutputStream output) { this.output = output; } @Override public void write(int b) throws IOException { output.write(b); count++; } public long getCount() { return count; } } private long maxSize; private File targetDir; private int fileIndex = 1; private String charset; public ShiftWriter(File targetDir) throws FileNotFoundException, UnsupportedEncodingException { this(targetDir,DEFAUT_MAX_SIZE,DEFAULT_CHARSET); } public ShiftWriter(File targetDir, String charset) throws FileNotFoundException, UnsupportedEncodingException { this(targetDir,DEFAUT_MAX_SIZE,charset); } /** * 构造器函数,向指定的文件夹中写入文件,文件的数据量存在最大值,达到最大值后切换文件进行写入。 * @param targetDir 目标文件夹(目录) * @param maxSize 文件的数据最大值 * @param charset 文件采用的字符编码 */ public ShiftWriter(File targetDir, long maxSize, String charset) throws FileNotFoundException, UnsupportedEncodingException { if(maxSize<=0)throw new IllegalArgumentException("maxSize is wrong."); if(targetDir==null || !targetDir.exists() || !targetDir.isDirectory()){ throw new IllegalArgumentException("target dir isn't exists."); } this.maxSize = maxSize; this.charset = charset; this.targetDir = targetDir; File targets[] = targetDir.listFiles(); Pattern pattern = Pattern.compile("(\\d+)\\.(txt)"); for(File file : targets){ Matcher matcher = pattern.matcher(file.getName()); if(matcher.matches()){ int index = Integer.parseInt(matcher.group(1)); fileIndex = index>fileIndex?index:fileIndex; } } shiftTarget(); } private File targetFile; private BufferedOutputStream buffer; private CounterOutputStream counter; private OutputStreamWriter writer; private void shiftTarget() throws FileNotFoundException, UnsupportedEncodingException { do{ targetFile = new File(targetDir,fileIndex+".txt"); if(targetFile.exists() && targetFile.isFile()){ if(targetFile.length()>=maxSize){ fileIndex++; continue; } } break; }while(true); OutputStream output = new FileOutputStream(targetFile,true); buffer = new BufferedOutputStream(output); counter = new CounterOutputStream(buffer); writer = new OutputStreamWriter(counter, charset); } @Override public void write(char[] cbuf, int off, int len) throws IOException { writer.write(cbuf, off, len); writer.flush(); if(counter.count>=maxSize){ writer.close(); buffer.flush(); buffer.close(); fileIndex++; shiftTarget(); } } @Override public void flush() throws IOException { writer.flush(); buffer.flush(); } @Override public void close() throws IOException { writer.close(); buffer.close(); } /** 写入文件。将当前文件的数据写入到Writer中。 */ private static void writeFile(File src, Writer writer) throws IOException{ BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(src), "GBK")); int ch = -1; try{ while((ch=br.read())!=-1){ writer.write(ch); } }finally{ br.close(); } } /** * 递归遍历源文件夹,将txt文件的数据写入到Writer中。 * @param dir 源文件夹 * @param level 递归深度。遍历几层文件夹。当前文件夹的值为1. * @param writer 目标写入器(Writer) */ private static void mergeFiles(File dir, int level, Writer writer) throws IOException{ if(level<0)return; if(dir.isDirectory()){ for(File file : dir.listFiles()){ mergeFiles(file, level-1, writer); } } if(dir.isFile() && dir.getName().toLowerCase().endsWith(".txt")){ System.out.println(dir); writeFile(dir, writer); } } /** * 测试用例 */ public static void main(String[] args) throws IOException { File srcDir = new File("d:\\tmp\\examples"); File targetDir = new File("d:\\tmp\\shift"); Writer writer = new ShiftWriter(targetDir); try{ mergeFiles(srcDir, 2, writer); }finally{ writer.close(); } }} 大致的思路,谁都会说,就是具体的细节方面需要理清楚。1. 文本文件的字符处理,需要知道,文件的数据是存在字符编码的。 例如:GBK编码中,汉字是2字节、英文数字是1字节。2. 分割文件的时候,由于数据存在编码,就不能按字节大小精确分割。 因为,有可能将一个汉字的数据拆分到两个文件中,使得两个文件的末尾和开头出现乱码(半个汉字数据)。3. 既然不能精确分割,那么数据处理的时候,尽量面向字符编程而不是面向二进制流来编程。 但是,如果单纯面向字符编程时,又无法准确判断写入文件的二进制数据的大小。(汉字和英文混排的文本)4. 将文件的合并与分割分成两个部分进行编码开发。 一个部分的功能是将所有要求的文件数据写入到同一个Writer(面向字符编程)里。这个部分需要遍历文件夹,筛选出文本文件。递归遍历时,为防止递归死循环(其实该案例理论上是不会出现的),添加了递归深度参数,如果不限制递归深度,将该参数去掉即可。 另一个部分的功能是将输出的字符数据切换成多个文件进行存储。由于切换文件的规则是按照写入文件数据的最大值来进行切换的,那么,需要保存当前文件已经写入的数据量,这个数据量是二进制数据量,所以,构建了CounterOutputStream 这个类。利用OutputStreamWriter进行字符向二进制的转码,每写入一个字符都要进行一次转码(调用flush)。由于频繁flush输出的IO,从而引起写入数据的性能瓶颈,所以,创建了BufferedOutputStream,用了提升写入性能。5. 所有的技术环节都弄清楚了,剩下的就是将这些功能代码进行归类、封装、组合、调用了。 我自己是用楼上临时文件的方法实现的,但是调用delete方法删不掉那个临时文件,还有其他的一些问题没解决,期待大神的demo供本人参考哈 [请教]关天时间函数输出问题 求一个实现数组的逆序排列的程序!!! 如何运行EXCEL文件 关于TimerTask和SWT的一个调用问题 [转帖]一百万元的首页,打造网络神话,把不可能变成可能 请问如何在application中在jbutton上贴个图片? 一个很菜的问题 谁给我一份gui界面的数据库操作java源代码,我出500分! 怎么实现在javabean里操作注册oracle的数据库用户!! 高手救我吧!!!! java 自动化测试 是什么? 多态问题
然后继续遍历创建文本文档,(每读取1mb的内容就创建一个txt,写入1mb)
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;/**
* 自定义功能的Writer , 可以随着写入文件的大小切换新文件进行输出。
*/
public class ShiftWriter extends Writer{ public static final long DEFAUT_MAX_SIZE = 1*1024*1024;
public static final String DEFAULT_CHARSET = "GBK";
/** 可计数的输出流 */
static class CounterOutputStream extends OutputStream{
private OutputStream output;
private long count=0;
public CounterOutputStream(OutputStream output) {
this.output = output;
} @Override
public void write(int b) throws IOException {
output.write(b);
count++;
}
public long getCount() {
return count;
}
}
private long maxSize;
private File targetDir;
private int fileIndex = 1;
private String charset;
public ShiftWriter(File targetDir) throws FileNotFoundException, UnsupportedEncodingException {
this(targetDir,DEFAUT_MAX_SIZE,DEFAULT_CHARSET);
}
public ShiftWriter(File targetDir, String charset) throws FileNotFoundException, UnsupportedEncodingException {
this(targetDir,DEFAUT_MAX_SIZE,charset);
}
/**
* 构造器函数,向指定的文件夹中写入文件,文件的数据量存在最大值,达到最大值后切换文件进行写入。
* @param targetDir 目标文件夹(目录)
* @param maxSize 文件的数据最大值
* @param charset 文件采用的字符编码
*/
public ShiftWriter(File targetDir, long maxSize, String charset) throws FileNotFoundException, UnsupportedEncodingException {
if(maxSize<=0)throw new IllegalArgumentException("maxSize is wrong.");
if(targetDir==null || !targetDir.exists() || !targetDir.isDirectory()){
throw new IllegalArgumentException("target dir isn't exists.");
}
this.maxSize = maxSize;
this.charset = charset;
this.targetDir = targetDir;
File targets[] = targetDir.listFiles();
Pattern pattern = Pattern.compile("(\\d+)\\.(txt)");
for(File file : targets){
Matcher matcher = pattern.matcher(file.getName());
if(matcher.matches()){
int index = Integer.parseInt(matcher.group(1));
fileIndex = index>fileIndex?index:fileIndex;
}
}
shiftTarget();
}
private File targetFile;
private BufferedOutputStream buffer;
private CounterOutputStream counter;
private OutputStreamWriter writer;
private void shiftTarget() throws FileNotFoundException, UnsupportedEncodingException {
do{
targetFile = new File(targetDir,fileIndex+".txt");
if(targetFile.exists() && targetFile.isFile()){
if(targetFile.length()>=maxSize){
fileIndex++;
continue;
}
}
break;
}while(true);
OutputStream output = new FileOutputStream(targetFile,true);
buffer = new BufferedOutputStream(output);
counter = new CounterOutputStream(buffer);
writer = new OutputStreamWriter(counter, charset);
} @Override
public void write(char[] cbuf, int off, int len) throws IOException {
writer.write(cbuf, off, len);
writer.flush();
if(counter.count>=maxSize){
writer.close();
buffer.flush();
buffer.close();
fileIndex++;
shiftTarget();
}
} @Override
public void flush() throws IOException {
writer.flush();
buffer.flush();
} @Override
public void close() throws IOException {
writer.close();
buffer.close();
}
/** 写入文件。将当前文件的数据写入到Writer中。 */
private static void writeFile(File src, Writer writer) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(src), "GBK"));
int ch = -1;
try{
while((ch=br.read())!=-1){
writer.write(ch);
}
}finally{
br.close();
}
}
/**
* 递归遍历源文件夹,将txt文件的数据写入到Writer中。
* @param dir 源文件夹
* @param level 递归深度。遍历几层文件夹。当前文件夹的值为1.
* @param writer 目标写入器(Writer)
*/
private static void mergeFiles(File dir, int level, Writer writer) throws IOException{
if(level<0)return;
if(dir.isDirectory()){
for(File file : dir.listFiles()){
mergeFiles(file, level-1, writer);
}
}
if(dir.isFile() && dir.getName().toLowerCase().endsWith(".txt")){
System.out.println(dir);
writeFile(dir, writer);
}
}
/**
* 测试用例
*/
public static void main(String[] args) throws IOException {
File srcDir = new File("d:\\tmp\\examples");
File targetDir = new File("d:\\tmp\\shift");
Writer writer = new ShiftWriter(targetDir);
try{
mergeFiles(srcDir, 2, writer);
}finally{
writer.close();
}
}
}
1. 文本文件的字符处理,需要知道,文件的数据是存在字符编码的。
例如:GBK编码中,汉字是2字节、英文数字是1字节。
2. 分割文件的时候,由于数据存在编码,就不能按字节大小精确分割。
因为,有可能将一个汉字的数据拆分到两个文件中,使得两个文件的末尾和开头出现乱码(半个汉字数据)。
3. 既然不能精确分割,那么数据处理的时候,尽量面向字符编程而不是面向二进制流来编程。
但是,如果单纯面向字符编程时,又无法准确判断写入文件的二进制数据的大小。(汉字和英文混排的文本)
4. 将文件的合并与分割分成两个部分进行编码开发。
一个部分的功能是将所有要求的文件数据写入到同一个Writer(面向字符编程)里。这个部分需要遍历文件夹,筛选出文本文件。递归遍历时,为防止递归死循环(其实该案例理论上是不会出现的),添加了递归深度参数,如果不限制递归深度,将该参数去掉即可。
另一个部分的功能是将输出的字符数据切换成多个文件进行存储。由于切换文件的规则是按照写入文件数据的最大值来进行切换的,那么,需要保存当前文件已经写入的数据量,这个数据量是二进制数据量,所以,构建了CounterOutputStream 这个类。利用OutputStreamWriter进行字符向二进制的转码,每写入一个字符都要进行一次转码(调用flush)。由于频繁flush输出的IO,从而引起写入数据的性能瓶颈,所以,创建了BufferedOutputStream,用了提升写入性能。
5. 所有的技术环节都弄清楚了,剩下的就是将这些功能代码进行归类、封装、组合、调用了。
期待大神的demo供本人参考哈