在操作系统里面有一个copy命令,这个命令的主要功能是可以实现文件的拷贝处理,现在要求模拟这个命令,通过初始化参数输入拷贝的源文件路径与拷贝的目标路径实现文件的拷贝处理。
需求分析:
需要实现文件的拷贝操作,那么这种拷贝就有可能拷贝各种类型的文件,所以肯定使用字节流;
在进行拷贝的时候有可能需要考虑到大文件的拷贝问题;
实现方案:
方案一:
使用InputStream将全部要拷贝的内容直接读取到程序里面,而后一次性的输出到目标文件。
如果现在拷贝的文件很大,基本上程序就死了;
(存在 do…while问题,一般不使用)
package cn.mldn.demo;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
class FileUtil { // 定义一个文件操作的工具类
private File srcFile ; // 源文件路径
private File desFile ; // 目标文件路径
public FileUtil(String src,String des) {
this(new File(src),new File(des));
}
public FileUtil(File srcFile,File desFile) {
this.srcFile = srcFile;
this.desFile = desFile;
}
public boolean copy() throws Exception { // 文件拷贝处理
if (!this.srcFile.exists()) { // 源文件必须存在!
System.out.println("拷贝的源文件不存在!");
return false ; // 拷贝失败
}
if (!this.desFile.getParentFile().exists()) {
this.desFile.getParentFile().mkdirs(); // 创建父目录
}
byte data [] = new byte[1024] ; // 开辟一个拷贝的缓冲区
InputStream input = null ;
OutputStream output = null ;
try {
input = new FileInputStream(this.srcFile);
output = new FileOutputStream(this.desFile);
int len = 0;
do {
len = input.read(data) ; // 拷贝的内容都在data数组
if (len != -1) {
output.write(data,0,len);
}
} while (len != -1);
return true ;
} catch (Exception e) {
throw e ;
} finally {
if (input != null) {
input.close();
}
if (output != null) {
output.close();
}
}
}
}
public class JavaAPIDemo {
public static void main(String[] args) throws Exception {
if (args.length != 2) { // 程序执行出错
System.out.println("命令执行错误,执行结构,java JavaAPIDemo 拷贝源文件路径拷贝目标文件路径");
System.exit(1);
}
long start = System.currentTimeMillis();
FileUtil fu = new FileUtil(args[0],args[1]);
System.out.println(fu.copy() ? "文件拷贝成功" : "文件拷贝失败!");
long end = System.currentTimeMillis();
System.out.println("拷贝完成的时间:" + (end - start));
}
}
方案二:
采用部分拷贝,读取一部分输出一部分数据,如果现在要采用第二种做法,核心的操作方法:
InputStream:public int read(byte[] b) throws IOException;
OutputStream:public void write(byte[] b, int off, int len) throws IOException。
范例:实现文件拷贝处理
package cn.mldn.demo;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
class FileUtil { // 定义一个文件操作的工具类
private File srcFile ; // 源文件路径
private File desFile ; // 目标文件路径
public FileUtil(String src,String des) {
this(new File(src),new File(des));
}
public FileUtil(File srcFile,File desFile) {
this.srcFile = srcFile;
this.desFile = desFile;
}
public boolean copy() throws Exception { // 文件拷贝处理
if (!this.srcFile.exists()) { // 源文件必须存在!
System.out.println("拷贝的源文件不存在!");
return false ; // 拷贝失败
}
if (!this.desFile.getParentFile().exists()) {
this.desFile.getParentFile().mkdirs(); // 创建父目录
}
byte data [] = new byte[1024] ; // 开辟一个拷贝的缓冲区
InputStream input = null ;
OutputStream output = null ;
try {
input = new FileInputStream(this.srcFile);
output = new FileOutputStream(this.desFile);
int len = 0;
// 1。读取数据到数组之中,随后返回读取的个数、len = input.read(data)
// 2。判断个数是否是-1,如果 不是则进行写入、len = input.read(data) != -1
while ((len = input.read(data)) != -1) {
output.write(data,0,len);
}
return true ;
} catch (Exception e) {
throw e ;
} finally {
if (input != null) {
input.close();
}
if (output != null) {
output.close();
}
}
}
}
public class JavaAPIDemo {
public static void main(String[] args) throws Exception {
if (args.length != 2) { // 程序执行出错
System.out.println("命令执行错误,执行结构,java JavaAPIDemo 拷贝源文件路径拷贝目标文件路径");
System.exit(1);
}
long start = System.currentTimeMillis();
FileUtil fu = new FileUtil(args[0],args[1]);
System.out.println(fu.copy() ? "文件拷贝成功" : "文件拷贝失败!");
long end = System.currentTimeMillis();
System.out.println("拷贝完成的时间:" + (end - start));
}
}
但是需要注意的是,以上的做法是属于文件拷贝的最原始实现,而从JDK1.9开始InputStream和Reader类中都追加有数据转存的处理操作方法:
InputStream:public long transferTo(OutputStream out) throws IOException;
Reader:public long transferTo(Writer out) throws IOException;
范例:使用转存的方式处理
package cn.mldn.demo;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
class FileUtil { // 定义一个文件操作的工具类
private File srcFile ; // 源文件路径
private File desFile ; // 目标文件路径
public FileUtil(String src,String des) {
this(new File(src),new File(des));
}
public FileUtil(File srcFile,File desFile) {
this.srcFile = srcFile;
this.desFile = desFile;
}
public boolean copy() throws Exception { // 文件拷贝处理
if (!this.srcFile.exists()) { // 源文件必须存在!
System.out.println("拷贝的源文件不存在!");
return false ; // 拷贝失败
}
if (!this.desFile.getParentFile().exists()) {
this.desFile.getParentFile().mkdirs(); // 创建父目录
}
InputStream input = null ;
OutputStream output = null ;
try {
input = new FileInputStream(this.srcFile);
output = new FileOutputStream(this.desFile);
input.transferTo(output);
return true ;
} catch (Exception e) {
throw e ;
} finally {
if (input != null) {
input.close();
}
if (output != null) {
output.close();
}
}
}
}
public class JavaAPIDemo {
public static void main(String[] args) throws Exception {
if (args.length != 2) { // 程序执行出错
System.out.println("命令执行错误,执行结构,java JavaAPIDemo 拷贝源文件路径拷贝目标文件路径");
System.exit(1);
}
long start = System.currentTimeMillis();
FileUtil fu = new FileUtil(args[0],args[1]);
System.out.println(fu.copy() ? "文件拷贝成功" : "文件拷贝失败!");
long end = System.currentTimeMillis();
System.out.println("拷贝完成的时间:" + (end - start));
}
}
此时千万要注意程序的运行版本问题。那么如果说现在对此程序要求进一步扩展,可以实现一个文件目录的拷贝呢?一旦进行了文件目录的拷贝还需要拷贝所有的子目录中的文件。
范例:文件夹拷贝
package cn.mldn.demo;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
class FileUtil { // 定义一个文件操作的工具类
private File srcFile ; // 源文件路径
private File desFile ; // 目标文件路径
public FileUtil(String src,String des) {
this(new File(src),new File(des));
}
public FileUtil(File srcFile,File desFile) {
this.srcFile = srcFile;
this.desFile = desFile;
}
public boolean copyDir() throws Exception {
try {
this.copyImpl(this.srcFile) ;
return true ;
} catch (Exception e) {
return false ;
}
}
private void copyImpl(File file) throws Exception { // 递归操作
if (file.isDirectory()) { // 是目录
File results [] = file.listFiles(); // 列出全部目录组成
if (results != null) {
for (int x = 0; x < results.length; x++) {
copyImpl(results[x]);
}
}
} else { // 是文件
String newFilePath = file.getPath().replace(this.srcFile.getPath() + File.separator,"");
File newFile = new File(this.desFile,newFilePath); // 拷贝的目标路径
this.copyFileImpl(file, newFile) ;
}
}
private boolean copyFileImpl(File srcFile,File desFile) throws Exception {
if (!desFile.getParentFile().exists()) {
desFile.getParentFile().mkdirs(); // 创建父目录
}
InputStream input = null ;
OutputStream output = null ;
try {
input = new FileInputStream(srcFile);
output = new FileOutputStream(desFile);
input.transferTo(output);
return true ;
} catch (Exception e) {
throw e ;
} finally {
if (input != null) {
input.close();
}
if (output != null) {
output.close();
}
}
}
public boolean copy() throws Exception { // 文件拷贝处理
if (!this.srcFile.exists()) { // 源文件必须存在!
System.out.println("拷贝的源文件不存在!");
return false ; // 拷贝失败
}
return this.copyFileImpl(this.srcFile, this.desFile) ;
}
}
public class JavaAPIDemo {
public static void main(String[] args) throws Exception {
if (args.length != 2) { // 程序执行出错
System.out.println("命令执行错误,执行结构,java JavaAPIDemo 拷贝源文件路径拷贝目标文件路径");
System.exit(1);
}
long start = System.currentTimeMillis();
FileUtil fu = new FileUtil(args[0],args[1]);
if (new File(args[0]).isFile()) {
System.out.println(fu.copy() ? "文件拷贝成功" : "文件拷贝失败!");
}else {
System.out.println(fu.copyDir() ? "文件夹拷贝成功" : "文件夹拷贝失败!");
}
long end = System.currentTimeMillis();
System.out.println("拷贝完成的时间:" + (end - start));
}
}
本程序是IO操作的核心代码,本程序可以理解,整个的IO处理机制就非常容易理解了。