java 多线程文件复制
目标是用多线程实现文件读取和写入,但是,实际却发现,java的io并不允许多线程同时写入,读取可以,本来想要 写个比操作系统快的复制功能,代码只实现了基本版本,还有缺陷,以后会继续完善,如果大家有更快速写入文件的方法,一定要留言哦
在目前没有多线程写入的前提下,读取后写入队列然后再起一个线程写文件会比现在的代码要快,但是也不是我想要的并发写入,大家有没有更好的解决方案。nio中的FileChannel.transferTo,经过测试,写入也是阻塞其他线程的
1 import java.io.File; 2 import java.io.FileInputStream; 3 import java.math.BigInteger; 4 import java.security.MessageDigest; 5 6 public class Digest { 7 public static String getFileMD5(File file) { 8 if (!file.isFile()) { 9 return null; 10 } 11 MessageDigest digest = null; 12 FileInputStream in = null; 13 byte buffer[] = new byte[8192]; 14 int len; 15 try { 16 digest = MessageDigest.getInstance("MD5"); 17 in = new FileInputStream(file); 18 while ((len = in.read(buffer)) != -1) { 19 digest.update(buffer, 0, len); 20 } 21 BigInteger bigInt = new BigInteger(1, digest.digest()); 22 return bigInt.toString(16); 23 } catch (Exception e) { 24 e.printStackTrace(); 25 return null; 26 } finally { 27 try { 28 in.close(); 29 } catch (Exception e) { 30 e.printStackTrace(); 31 } 32 } 33 } 34 35 public static String getFileSha1(File file) { 36 if (!file.isFile()) { 37 return null; 38 } 39 MessageDigest digest = null; 40 FileInputStream in = null; 41 byte buffer[] = new byte[8192]; 42 int len; 43 try { 44 digest = MessageDigest.getInstance("SHA-1"); 45 in = new FileInputStream(file); 46 while ((len = in.read(buffer)) != -1) { 47 digest.update(buffer, 0, len); 48 } 49 BigInteger bigInt = new BigInteger(1, digest.digest()); 50 return bigInt.toString(16); 51 } catch (Exception e) { 52 e.printStackTrace(); 53 return null; 54 } finally { 55 try { 56 in.close(); 57 } catch (Exception e) { 58 e.printStackTrace(); 59 } 60 } 61 } 62 }
1 import java.io.File; 2 import java.io.FileInputStream; 3 import java.io.FileNotFoundException; 4 import java.io.IOException; 5 import java.io.InputStream; 6 import java.io.RandomAccessFile; 7 import java.text.DecimalFormat; 8 9 public class CopyFile { 10 11 private String fileName = ""; 12 private int buffSize = 1024; 13 private long fileSize = 0; 14 private int threadNum = 2; 15 private String newName = ""; 16 private String newPath = ""; 17 private String copyIn = ""; 18 private boolean showProgress = true; 19 private boolean end = false; 20 long stime = 0; 21 long etime = 0; 22 private long copySize = 0; 23 private File srcfile = null; 24 File newFile = null; 25 File filecopyIn = null; 26 27 public CopyFile(String filePath) { 28 this.fileName = filePath; 29 } 30 31 public CopyFile(String filePath, int threadNum) { 32 this.fileName = filePath; 33 this.threadNum = threadNum; 34 } 35 36 public CopyFile(String filePath, int threadNum, int buffSize) { 37 this.fileName = filePath; 38 this.buffSize = buffSize; 39 this.threadNum = threadNum; 40 } 41 42 public void to() throws IOException { 43 if (newPath == null || "".equals(newPath)) { 44 newPath = new File(fileName).getParent(); 45 to(newPath); 46 } 47 } 48 49 public void to(String newPath) throws IOException { 50 if (!new File(newPath).isDirectory()) { 51 throw new IOException("目标必须为目录"); 52 } 53 srcfile = new File(fileName); 54 stime = System.currentTimeMillis(); 55 this.newName = newFileName(newPath, fileName); 56 copyIn = newName + ".copyIN"; 57 newFile = new File(newName); 58 if (newFile.exists()) { 59 newFile.delete(); 60 } 61 filecopyIn = new File(copyIn); 62 if (filecopyIn.exists()) { 63 filecopyIn.delete(); 64 } 65 66 InputStream in = new FileInputStream(srcfile); 67 fileSize = in.available(); 68 for (int i = 0; i < threadNum; i++) { 69 long s = fileSize / threadNum * i; 70 long e = fileSize / threadNum * (i + 1) 71 + (i == threadNum - 1 ? fileSize % threadNum : 0); 72 new copyThread(s, e); 73 } 74 if (showProgress) 75 new Progress().start(); 76 77 } 78 79 private String newFileName(String newPath2, String fileName2) { 80 String tmp = srcfile.getName(); 81 int suffixIndex = tmp.lastIndexOf("."); 82 if (suffixIndex > -1) { 83 tmp = tmp.substring(0, suffixIndex) + " copy" 84 + tmp.substring(suffixIndex, tmp.length()); 85 } else { 86 tmp += " copy"; 87 } 88 if (!newPath2.endsWith(File.separatorChar + "")) 89 newPath2 += File.separatorChar; 90 return newPath2 + tmp; 91 } 92 93 public long end() { 94 long newFileLength = 0; 95 if (filecopyIn.renameTo(newFile)) { 96 newFileLength = newFile.length(); 97 } else { 98 System.out.println("重命名失败"); 99 newFileLength = filecopyIn.length(); 100 } 101 long time = System.currentTimeMillis(); 102 etime = time; 103 long haoshi = (etime - stime); 104 System.out.println("用时=" + haoshi + "毫秒"); 105 System.out.println("源文件:" + fileSize + " 复制的文件:" + newFileLength 106 + " 丢失:" + (fileSize - newFileLength)); 107 System.out 108 .println("文件:" 109 + Digest.getFileMD5(srcfile).equals( 110 Digest.getFileMD5(newFile))); 111 end = true; 112 return haoshi; 113 } 114 115 class Progress extends Thread { 116 public void run() { 117 DecimalFormat df = new DecimalFormat("0"); 118 while (!end) { 119 long progress = Integer.parseInt(df.format((float) copySize 120 / fileSize * 100)); 121 System.out.println(progress + "%"); 122 if (progress == 100) 123 end(); 124 try { 125 sleep(1000); 126 } catch (InterruptedException e) { 127 e.printStackTrace(); 128 } 129 } 130 } 131 } 132 133 class copyThread extends Thread { 134 private RandomAccessFile in = null; 135 private RandomAccessFile out = null; 136 private long startOff = 0, endOff = 0; 137 private byte[] buff; 138 139 public copyThread(long startOff, long endOff) { 140 try { 141 this.startOff = startOff; 142 this.endOff = endOff; 143 in = new RandomAccessFile(fileName, "r"); 144 in.seek(startOff); 145 out = new RandomAccessFile(copyIn, "rwd"); 146 out.seek(startOff); 147 start(); 148 } catch (FileNotFoundException e) { 149 e.printStackTrace(); 150 } catch (IOException e) { 151 e.printStackTrace(); 152 } 153 } 154 155 public void run() { 156 try { 157 System.out.println("start=" + startOff + " end=" + endOff); 158 buff = new byte[buffSize]; 159 long currentThreadTotal = endOff - startOff; 160 long yu = currentThreadTotal % buffSize; 161 int off = buffSize; 162 long forCount = currentThreadTotal / buffSize 163 + (yu > 0 ? 1 : 0); 164 for (long i = 0; i < forCount; i++) { 165 off = (int) (i == forCount - 1 && yu > 0 ? yu : buffSize); 166 int rd = in.read(buff, 0, off); 167 if (rd != -1) 168 out.write(buff, 0, rd); 169 if (showProgress) { 170 synchronized (this) { 171 copySize += rd; 172 } 173 } 174 yield(); 175 } 176 177 in.close(); 178 out.close(); 179 // end(); 180 } catch (Exception e) { 181 e.printStackTrace(); 182 } 183 } 184 } 185 186 public static void main(String[] args) { 187 String y = "e:/baidu download/贫民窟的百万富翁.rmvb"; 188 String n = "e:/baidu download/"; 189 CopyFile cf = new CopyFile(y, 3, 1024 * 1024 * 10); 190 try { 191 cf.to(); 192 } catch (IOException e) { 193 e.printStackTrace(); 194 } 195 196 } 197 }