java 通過流, nio 移動文件或者文件夾

我們用例子說明java怎樣通過不同的方式移動文件或文件夾。

[b]首先, 我們先介紹通過流的例子[/b],你可以很容易把指定的源文件或文件夾移動到目標文件夾中。
程序中, 你需要指定源文件/文件夾和目標文件夾的絕對路徑。 如果指定的源文件(夾)不存在, 程序打印出提示信息"File or directory does not exist.", 然後從控制檯中推出程序。 如果指定的目標文件夾不存在,程序會提示你是否創建一個新的文件夾。 通過輸入"y", 程序就會爲你創建一個新的文件夾並且把源文件全部移動到目標文件夾中。 當目標文件夾存在時, 它會徵詢你是否替換掉已經存在的文件夾。

package io;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;

import javax.swing.JOptionPane;

public class MovingFile {

public static void main(String[] args) throws IOException {

int a = 0;

BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
System.out
.print("Enter the file or directory name that has to be moved : ");

String src = in.readLine();

if (src.equals("")) {

System.out.println("Invalid directory or file name.");

System.exit(0);

}

File source = new File(src);

if (!source.exists()) {

System.out.println("File or directory does not exist.");

System.exit(0);

}

System.out
.print("Enter the complete path where file or directory has to be moved: ");

String dest = in.readLine();

if (dest.equals("")) {

System.out.println("Invalid directory or file name.");

System.exit(0);

}

File destination = new File(dest);

if (!destination.exists()) {

System.out
.print("Mentioned directory does not exist. \nDo you want to create a new directory(Y/N)? ");

String chk = in.readLine();

if (chk.equals("Y") || chk.equals("y")) {

destination.mkdir();

copyDirectory(source, destination);

a = 1;

}

else if (chk.equals("N") || chk.equals("n")) {

System.exit(0);

}

else {

System.out.println("Invalid Entry!");

System.exit(0);

}

}

else {

int num = JOptionPane
.showConfirmDialog(null,
"Given file or folder name already exists. \nDo you want to replace now?");

if (num == 0) {

copyDirectory(source, destination);

a = 1;

}

}

if (a == 1) {

System.out.println("File or directory moved successfully.");

if (!delete(source)) {

throw new IOException("Unable to delete original folder");

}

} else if (a == 0) {

System.exit(0);

}

}

public static void copyDirectory(File sourceDir, File destDir)
throws IOException {

if (!destDir.exists()) {

destDir.mkdir();

}

File[] children = sourceDir.listFiles();

for (File sourceChild : children) {

String name = sourceChild.getName();

File destChild = new File(destDir, name);

if (sourceChild.isDirectory()) {

copyDirectory(sourceChild, destChild);

}

else {

copyFile(sourceChild, destChild);

}

}

}

public static void copyFile(File source, File dest) throws IOException {

if (!dest.exists()) {

dest.createNewFile();

}

InputStream in = null;

OutputStream out = null;

try {

in = new FileInputStream(source);

out = new FileOutputStream(dest);

byte[] buf = new byte[1024];

int len;

while ((len = in.read(buf)) > 0) {

out.write(buf, 0, len);

}

}

finally {

in.close();

out.close();

}

}

public static boolean delete(File resource) throws IOException {

if (resource.isDirectory()) {

File[] childFiles = resource.listFiles();

for (File child : childFiles) {

delete(child);

}

}

return resource.delete();

}

}



[b]File object 有個方法叫renameTo[/b], 但這個方法是平臺相關的。 我在windows 平臺上測試過可以成功。 但沒在linux上測試, 所以不清楚這個方法在其它平臺上運行的結果。 要是有測試過的朋友, 可以給我留言。 謝謝。
如果可以用這個方法的話, 那方法 copyFile(File source, File dest) 就很簡單了, 只需寫成:


public static void copyFile(File source, File dest) throws IOException {
source.renameTo(dest);
}



[b]通過NIO的方。[/b]
流移動文件, 有個潛在的性能問題, 主要是緩存的原因。 在實際情況下, 需要優化緩存的大小以達到最優的情況。 一般文件不是很大的情況, 在windons下, 2k比較快。NIO就不需要人爲的設置緩存了。 但nio的話, 對於超大文件, 幾百M或者上G的話, 性能不是很樂觀。 但小文件的話, 如果流的緩存沒有配置好。nio 的性能是很快的。下面我們用nio的方式新建一個方法替換 copyFile(File source, File dest):

public static void copyFileWithNIO(File sourceFile, File destFile)
throws IOException {

if (!destFile.exists()) {
destFile.createNewFile();
}

FileChannel source = null;
FileChannel destination = null;
long count = 0;
try {
source = new FileInputStream(sourceFile).getChannel();
long size = source.size();
destination = new FileOutputStream(destFile).getChannel();
while( (count += destination.transferFrom(source, count, size-count)) < size );
} finally {
if (source != null) {
source.close();
}
if (destination != null) {
destination.close();
}
}

}
 

但是, Windows, based on configuration, uses either executes a native copy or does the Stream-based copy. Solaris and AIX always uses the Channel implementation.
所以, 對於移動大文件的話, 最好是用流的方式。 那我們乾脆判斷一下, 如果是大文件, 就用流, 否則就用nio的方式。 我們對copyDirectory(File sourceDir, File destDir)方法改造下:

public static void copyDirectory(File sourceDir, File destDir)
throws IOException {

if (!destDir.exists()) {

destDir.mkdir();

}

File[] children = sourceDir.listFiles();

for (File sourceChild : children) {

String name = sourceChild.getName();

File destChild = new File(destDir, name);

if (sourceChild.isDirectory()) {

copyDirectory(sourceChild, destChild);

}

else {
long fileSize = sourceChild.length();

// for larger files (20Mb) use streams
if ( fileSize > 20971520l )
copyFile(sourceChild, destChild);
else
copyFileWithNIO (sourceChild, destChild);
}

}

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章