2.7 打印流
package cn.itcast.day159.stream;
import java.io.*;
import java.util.Scanner;
/*
* 三个常量
* 1、System.in
* 2、System.out
* 3、System.err
* 其中后面两个实质上没有区别,只是会给错误加上颜色以示区别
* FileDescriptor.out:表示控制台输出
* FileDescriptor.in:表示控制台输入
* */
public class Demo03 {
public static void main(String[] args) throws FileNotFoundException {
test1();
}
public static void test3() throws FileNotFoundException{
System.out.println("test");//输出到控制台
//重定向
File src = new File("D:/FQ/parent/data.txt");
//true表示自动刷新
System.setOut(new PrintStream(new BufferedOutputStream(new FileOutputStream(src)), true));
System.out.println("test");//打印输出到文件
//再次重定向到控制台
System.setOut(new PrintStream(new BufferedOutputStream(new FileOutputStream(FileDescriptor.out)), true));
System.out.println("test");
}
public static void test2() {
InputStream is = System.in;//标准键盘输入
//is = new BufferedInputStream(new FileInputStream("D:/FQ/parent/data.txt"));
Scanner sc = new Scanner(is);//这里is是一个输入流,于是我们可以替换为其他的输入流,比如文件输入流,如上
System.out.println("请输入: ");
System.out.println(sc.nextLine());
}
public static void test1(){
System.out.println("test");
System.err.println("err");//会自动加上颜色
}
}
说明:打印流也是一个处理流,这个流方便我们控制输入输出的位置。使用较为简单,这里不多数。
三、文件夹拷贝
在对文件夹进行拷贝的时候我们不仅要拷贝子孙目录,同时对于目录中的文件也需要进行拷贝。
package cn.itcast.day146.stream;
import java.io.File;
import java.io.IOException;
//文件夹的拷贝
//如果目标是一个文件夹则我们需要创建,如果是一个文件则直接拷贝即可
public class DirCopy {
public static void main(String[] args) {
String srcPath = "D:/FQ/parent";
File src = new File(srcPath);
String destPath = "D:/FQ/parent_back";
File dest = new File(destPath);
copy(src, dest);
}
//拷贝文件夹
private static void copyDir(File src, File dest) {
if(src.isFile()){
try {
FileCopyUtil.fileCopy(src, dest);
} catch (IOException e) {
e.printStackTrace();
}
}else if(src.isDirectory()){
//确保目标文件夹存在
dest.mkdirs();
//获取子孙级
for(File sub : src.listFiles()){
copyDir(sub, new File(dest, sub.getName()));
}
}
}
//封装成一个工具类
public static void copy(File src, File dest){
//之所以有下面这个判断,是因为我们不仅需要将源文件夹中内容拷贝,
//同时还要将源文件夹拷贝,也就是要将最上一级的目录拷贝下来
if(src.isDirectory()){//如果是目录
dest = new File(dest, src.getName());
System.out.println(dest);//D:\FQ\parent_back\parent
}
copyDir(src, dest);
}
public static void copy(String srcPath, String destPath){
File src = new File(srcPath);
File dest = new File(destPath);
copy(src, dest);
}
}
说明:程序中对文件的拷贝可以使用之前的程序,这里就不再给出了。
四、文件的分割与合并
package cn.itcast.day159.stream;
import java.io.*;
import java.util.*;
import cn.itcast.day189.socket_.CloseUtil;
public class Demo07 {
private String filePath;// 文件的路径
private long blockSize;// 每块的大小
private int size;// 块数
private List blockPath;// 各块的名字
private String fileName;// 文件名
private long length;// 文件大小
private String destPath;//分割后的存放目录
public Demo07() {
blockPath = new ArrayList();
}
public Demo07(String filePath, String destPath) {
this(filePath, 1024, destPath);
}
public Demo07(String filePath, long blockSize, String destPath) {
this.filePath = filePath;
this.destPath = destPath;
this.blockSize = blockSize;
init();
}
// 初始化操作,计算块数和文件名
public void init() {
File src = null;
if (filePath == null || !((src = new File(filePath)).exists())) {
return;
}
// 如果不是文件,而是目录,不能分割
if (src.isDirectory()) {
return;
}
// 文件名
this.fileName = src.getName();
// 计算块数
this.length = src.length();
// 如果blockSize比文件实际大小还大
if (this.blockSize > length) {
this.blockSize = length;
}
// 确定块数,ceil表示取大于等于参数值的最小整数,两个整数相除的时候有可能为0,这里乘上一个1.0
this.size = (int) (Math.ceil(length * 1.0 / this.blockSize));
initPathName();// 确定文件路径
}
private void initPathName() {
for (int i = 0; i < size; i++) {
String str = this.destPath + "/" + this.fileName + ".part" + i;
this.blockPath.add(str);// 添加一个文件路径
}
}
// 文件分割
// 第几块、起始位置、实际大小
// destPath:分割文件的存放目录
public void split(String destPath) {
long beginPos = 0;// 起始点
long actualBlockSize = blockSize;// 实际大小
// 计算所有块的大小、索引、位置
for (int i = 0; i < size; i++) {
if (i == size - 1) {
actualBlockSize = this.length - beginPos;
}
splitDetail(i, beginPos, actualBlockSize);
beginPos += actualBlockSize;
}
}
/*
* 文件的拷贝
*/
private void splitDetail(int index, long beginPos, long actualBolockSize) {
// 创建源
File src = new File(this.filePath);
File dest = new File(this.blockPath.get(index));
RandomAccessFile raf = null;// 输入流
BufferedOutputStream bos = null;// 输出流
// 选择流
try {
raf = new RandomAccessFile(src, "r");
bos = new BufferedOutputStream(new FileOutputStream(dest));
// 读取文件
raf.seek(beginPos);//设置读取的起始位置
byte[] buffer = new byte[1024];
int len = 0;
while (-1 != (len = raf.read(buffer))) {
// 写出
if (actualBolockSize - len >= 0) {
bos.write(buffer, 0, len);
actualBolockSize -= len;
} else {
// 写出剩余量
bos.write(buffer, 0, (int) actualBolockSize);
break;
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
CloseUtil.closeAll(bos, raf);
}
}
// 文件的合并
public void mergeFile1(String destPath) {
// 创建源
File dest = new File(destPath);
// 选择流
BufferedInputStream bis = null;
BufferedOutputStream bos = null;// 输出流
try {
bos = new BufferedOutputStream(new FileOutputStream(dest, true));// true表示追加
for (int i = 0; i < this.blockPath.size(); i++) {
bis = new BufferedInputStream(new FileInputStream(
this.blockPath.get(i)));
byte[] buffer = new byte[1024];
int len = 0;
while (-1 != (len = bis.read(buffer))) {
bos.write(buffer, 0, len);
}
bos.flush();
CloseUtil.closeAll(bis);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
CloseUtil.closeAll(bos);
}
}
// 文件合并,使用SequenceInputStream
public void mergeFile2(String destPath) {
// 创建源
File dest = new File(destPath);
// 选择流
// 创建一个容器
Vector vi = new Vector();
SequenceInputStream sis = null;
BufferedOutputStream bos = null;// 输出流
try {
for (int i = 0; i < this.blockPath.size(); i++) {
vi.add(new BufferedInputStream(new FileInputStream(
this.blockPath.get(i))));
}
bos = new BufferedOutputStream(new FileOutputStream(dest, true));// true表示追加
sis = new SequenceInputStream(vi.elements());
byte[] buffer = new byte[1024];
int len = 0;
while (-1 != (len = sis.read(buffer))) {
bos.write(buffer, 0, len);
}
bos.flush();
CloseUtil.closeAll(sis);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
CloseUtil.closeAll(bos);
}
}
public static void main(String[] args) {
Demo07 file = new Demo07("D:/FQ/parent/copy.txt", 500, "D:/FQ/parent");
// System.out.println(file.size);
// file.split("D:/FQ/parent");// 给出存放目录
file.mergeFile1("D:/FQ/parent/merge.txt");
}
}
说明:
- 文件的分割时,我们使用了
RandomAccessFile
流,这个流可以设置读取文件的位置,便于进行文件的分割。而在文件合并的时候我们可以使用一般的方式,也可以使用SequenceInputStream
这个类,这个流是一个合并流。