java的io,nio和commons的io比较总结

今天有个任务,有个120M左右,内含600多W条记录,记录之间按行分隔的文件,

分割成20W条记录每个文件,以便在其他程序中导入。

由于自己手残,机器上装了WIndows,配置还太差没法布hadoop,因此只能本机实现了。

使用java自身的IO和commons的IO实现了两套方法比较一下。

等回家之后,看看用hadoop的api能不能编起来简单一点

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. import java.io.*;  
  2. import java.util.*;  
  3.   
  4. import org.apache.commons.io.*;  
  5.   
  6. /** 
  7.  * 任务:将一个存储了大约600W行左右记录(120M)的文件按照20W行分割为若干个文件 
  8.  * @author RangE 
  9.  * 
  10.  */  
  11. public class BasicFileSplitter {  
  12.   
  13.     private BasicFileSplitter() {}  
  14.   
  15.     /** 
  16.      * 最基本的文件分割方法,使用BufferedReader和BufferedWriter 
  17.      * about 2700000ms cost on the task on Wed 13 Nov 2013 
  18.      *  
  19.      * 这个方法是最基本的IO,其性能瓶颈主要在于文件写入。 
  20.      * 写入文件使用的BufferedWriter使用字符流写入,但此处的实现是写一行就flush一次输出流,拖慢了写入速度 
  21.      *  
  22.      * @param inputPath 
  23.      * @param outputPath 
  24.      * @throws IOException 
  25.      */  
  26.     public static void splitFile(String inputPath, String outputPath) throws IOException {  
  27.         BufferedReader reader = null;  
  28.         BufferedWriter writer = null;  
  29.           
  30.         try {  
  31.             reader = new BufferedReader(new InputStreamReader(new FileInputStream(new File(inputPath)), "UTF-8"));  
  32.             String temp = "";  
  33.             int countFiles = 0;  
  34.             int countLines = 0;  
  35.               
  36.             System.out.println("Starting spliting files...");  
  37.                 while ((temp = reader.readLine()) != null) {  
  38.                     //System.out.println(temp);  
  39.                     writer = new BufferedWriter  
  40.                             (new OutputStreamWriter  
  41.                                     (new FileOutputStream(outputPath + countFiles + ".data"true), "UTF-8"));  
  42.                     writer.write(temp + "\n");  
  43.                     writer.flush();  
  44.                     countLines++;  
  45.                     if (countLines == 200000) {  
  46.                         System.out.println("Spliting file into parts: " + countFiles);  
  47.                         countFiles++;  
  48.                         countLines = 0;  
  49.                     }  
  50.                 }  
  51.                   
  52.         } finally {  
  53.             if (reader != null)  
  54.                 reader.close();  
  55.               
  56.             if (writer != null)  
  57.                 writer.close();  
  58.               
  59.             System.out.println("Spliting finished successfully.");  
  60.         }  
  61.     }  
  62.       
  63.     /** 
  64.      * 使用java.nio优化读写的分割 
  65.      * @param input 
  66.      * @param path 
  67.      */  
  68.     public static void splitFileByNewerIO(File input, String path) {  
  69.         //上网上查了一下:  
  70.         //要是需要一行一行处理的话还是用BufferedReader的readLine吧...  
  71.         //我试了试,用ByteBuffer的话,光处理分行问题就费不少时间.  
  72.         //原帖地址:http://bbs.csdn.net/topics/120096457  
  73.         //因此不予实现  
  74.     }  
  75.       
  76.     /** 
  77.      * 用org.apache.commons.io完成的文件分割 
  78.      * 17975ms cost on the task on Wed 13 Nov 2013 
  79.      *  
  80.      * Iterator读文件也是使用BufferedReader读取, 
  81.      * 可知主要的性能提升在于FileUtils的写(writeLines)方法,最终调用了IOUtils的writeLines使用BufferedOutputStream字节流写入 
  82.      *  
  83.      * 注:用此方法分割后,分割文件总大小略大于被分割文件大小 
  84.      *  
  85.      * @param inputPath 
  86.      * @param outputPath 
  87.      * @throws IOException 
  88.      */  
  89.     public static void splitFileByCommonsIO(String inputPath, String outputPath)   
  90.             throws IOException {  
  91.         LineIterator it = null;  
  92.         try {  
  93.             it = FileUtils.lineIterator(new File(inputPath), "UTF-8");  
  94.             int lineCounter = 0;  
  95.             int fileCounter = 0;  
  96.             List lineList = new ArrayList();  
  97.               
  98.             System.out.println("Starting..");  
  99.             while (it.hasNext()) {  
  100.                 lineList.add(it.nextLine());  
  101.                 lineCounter++;  
  102.                   
  103.                 if (lineCounter == 200000) {  
  104.                     FileUtils.writeLines(new File(outputPath + "_" + fileCounter), "UTF-8", lineList, true);  
  105.                     lineList.clear();  
  106.                     lineCounter = 0;  
  107.                     fileCounter++;  
  108.                     System.out.println("Complete file " + fileCounter);  
  109.                 }  
  110.             }  
  111.               
  112.             if (lineList != null && lineList.size() > 0) {  
  113.                 FileUtils.writeLines(new File(outputPath + "_" + fileCounter + 1), "UTF-8", lineList, true);  
  114.                 System.out.println("Complete the last file.");  
  115.             }  
  116.         } finally {  
  117.             if (it != null)  
  118.                 it.close();  
  119.             System.out.println("Task completed successfully.");  
  120.         }  
  121.     }  
  122. }  

后来又想比较一下java io,nio和commons io的读写速度,于是用三者分别做了一个复制文件的demo,如下

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. import java.io.*;  
  2. import java.nio.*;  
  3. import java.nio.channels.FileChannel;  
  4. import java.nio.charset.Charset;  
  5. import java.nio.charset.CharsetDecoder;  
  6. import java.nio.charset.CharsetEncoder;  
  7.   
  8. import org.apache.commons.io.FileUtils;  
  9. import org.apache.commons.io.LineIterator;  
  10.   
  11. public class FileRWSpeedCompare {  
  12.     private FileRWSpeedCompare() {}  
  13.   
  14.     /** 
  15.      * 单纯对文件的复制来比较io,nio和commons-io的读写速度 
  16.      * @param args 
  17.      * @throws IOException  
  18.      */  
  19.     public static void main(String[] args) throws IOException {  
  20.         // TODO Auto-generated method stub  
  21.         String in = "files/hehe.data";  
  22.         String out = in + "_copy";  
  23.           
  24.         long s = System.currentTimeMillis();  
  25.         //rw1(in, out);//Cost: 59797ms  
  26.         //rw2(in, out);//Cost: 4875ms  
  27.         //rw3(in, out);//Cost: 8796ms  
  28.         long e = System.currentTimeMillis();  
  29.         System.out.println("Cost: " + (e - s) + "ms");  
  30.     }  
  31.       
  32.     /** 
  33.      * 基本IO 
  34.      * @param inputPath 
  35.      * @param outputPath 
  36.      * @throws IOException  
  37.      */  
  38.     public static void rw1(String inputPath, String outputPath) throws IOException {  
  39.         BufferedReader reader = null;  
  40.         BufferedWriter writer = null;  
  41.   
  42.         try {  
  43.             reader = new BufferedReader(new InputStreamReader(new FileInputStream(new File(inputPath))));  
  44.             String temp = "";  
  45.             writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(outputPath))));  
  46.               
  47.             while ((temp = reader.readLine()) != null) {  
  48.                 writer.write(temp + "\n");  
  49.                 writer.flush();  
  50.             }  
  51.         } finally {  
  52.             if (reader != null)  
  53.                 reader.close();  
  54.             if (writer != null)  
  55.                 writer.close();  
  56.         }  
  57.     }  
  58.       
  59.     /** 
  60.      * NIO (http://www.cnblogs.com/focusj/archive/2011/11/03/2231583.html) 
  61.      * @param inputPath 
  62.      * @param outputPath 
  63.      * @throws IOException  
  64.      */  
  65.     public static void rw2(String inputPath, String outputPath) throws IOException {  
  66.         FileInputStream ins = new FileInputStream(inputPath);  
  67.         FileOutputStream outs = new FileOutputStream(outputPath);  
  68.         ByteBuffer buffer = ByteBuffer.allocate(1024);  
  69.           
  70.         FileChannel inc = ins.getChannel();  
  71.         FileChannel outc = outs.getChannel();  
  72.         Charset chs = Charset.forName("UTF-8");  
  73.           
  74.         CharsetDecoder dec = chs.newDecoder();  
  75.         CharsetEncoder enc = chs.newEncoder();  
  76.           
  77.         while (true) {  
  78.             buffer.clear();  
  79.               
  80.             CharBuffer cb = dec.decode(buffer);  
  81.             ByteBuffer bb = enc.encode(cb);  
  82.               
  83.             int temp = inc.read(bb);  
  84.             if (temp == -1break;  
  85.               
  86.             bb.flip();  
  87.             outc.write(bb);  
  88.         }  
  89.     }  
  90.       
  91.     /** 
  92.      * 使用FileUtils的copyFile方法,事实上这个方法就是用nio的Buffer和Channel实现的 
  93.      * @param inputPath 
  94.      * @param outputPath 
  95.      * @throws IOException 
  96.      */  
  97.     public static void rw3(String inputPath, String outputPath) throws IOException {  
  98.         FileUtils.copyFile(new File(inputPath), new File(outputPath));  
  99.     }  
  100. }  

(文中的代码如果有需要,可直接复制粘贴使用,需要导入 org.apache.commons.io包)


由此结果,我觉得,对于单纯的读写文件,或者读写内容较简单的文件,使用nio确实优于其他二者,比如复制文件的任务。

但是如果需要按行读取的较大文本文件并且对具体的行进行处理的话,或许commons io要更好一些,其对字节流的封装使用起来很方便。

commons io包还有很多方法,等着自己试一试:

http://m.blog.csdn.net/blog/FansUnion/9844977


【转载请注明出处,谢谢】

刚刚找到了:http://www.oschina.net/code/snippet_54100_7938 ,Java NIO按行读写打文件,测试一下,之后在修改这帖

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
当使用`transferTo()`方法将MultipartFile对象保存到目标文件时,如果目标文件已经存在,会抛出`java.nio.file.FileAlreadyExistsException`异常。 要解决这个问题,你可以考虑以下几种方法: 1. 删除目标文件:在调用`transferTo()`方法之前,先判断目标文件是否存在,如果存在则删除。可以使用`Files.deleteIfExists(Path path)`方法来删除文件。 ```java import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; // ... Path destPath = Path.of("目标文件路径"); if (Files.exists(destPath)) { Files.delete(destPath); } multipartFile.transferTo(destPath.toFile()); ``` 2. 使用不同的目标文件名:如果不要求使用相同的文件名保存上传的文件,可以为每个上传的文件生成一个唯一的文件名,避免文件重名。 ```java import java.util.UUID; import org.apache.commons.io.FilenameUtils; // ... String originalFilename = multipartFile.getOriginalFilename(); String extension = FilenameUtils.getExtension(originalFilename); String newFilename = UUID.randomUUID().toString() + "." + extension; Path destPath = Path.of("目标文件夹路径", newFilename); multipartFile.transferTo(destPath.toFile()); ``` 3. 覆盖目标文件:如果允许覆盖已存在的目标文件,可以使用`StandardCopyOption.REPLACE_EXISTING`选项来覆盖。 ```java import java.nio.file.StandardCopyOption; // ... Path destPath = Path.of("目标文件路径"); multipartFile.transferTo(destPath.toFile(), StandardCopyOption.REPLACE_EXISTING); ``` 根据你的具体需求,选择适合的解决方法来处理`java.nio.file.FileAlreadyExistsException`异常。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值