五、 Java IO
1. IO
1. java.io 包中几乎包含了所有操作输入、输出所需要的类
2. 一个流可以理解为一个数据的序列
3. 输入流表示从一个源读取数据,输出流表示向一个目标写数据
4. 字节流和字符流:
1)字节流:二进制,可处理一切文件(纯文本、音频、视频等)
2)字符流:纯文本,只能处理纯文本
5. 字节流、字符流与文件
1)字节流:
输入流:InputStream is = new FileInputStream(File file);
is.read(byte[] bt);// 从源中读取 bt.length 长度的字节并赋给数组 bt;返回读取的字节数;如果是文件结尾则返回 -1
输出流:OutputStream os = new FileOutputStream(File file, boolean append);
os.write(byte[] bt);// 将 bt 数组中 bt.length 长度的字节写入到目标中
2)字符流:
输入流:Reader reader = new FileReader(File file);
reader.read(char[] ch); // 从源中读取 ch.length 长度的字符并赋给数组 ch;返回读取的字符数;如果是文件结尾则返回 -1
输出流:Writer writer = new FileWriter(File file, boolean append);
writer.write(char[] ch);// 将 ch 数组中 ch.length 长度的字符写入到目标中
writer.append(CharSequence csq);// 追加字符序列,底层实现:writer.write(csq.toString());返回 Writer
6. 缓冲流:增加缓冲功能,避免频繁读写硬盘,提高性能
1)字节缓冲流
输入流:new BufferedInputStream(InputStream in);
输出流:new BufferedOutputStream(OutputStream out);
2)字符缓冲流
输入流:BufferedReader br = new BufferedReader(Reader in);
子类新增方法:br.readLine();// 无参数,行读取,返回 String 类型,如果是文件结尾则返回 null;不能发生多态
输出流:BufferedWriter bw = new BufferedWriter(Writer out);
子类新增方法:bw.newLine();// 无参数,相当于一个换行符,无返回类型;不能发生多态
7. 转换流:字节流转为字符流
1)编码与解码概念
编码:字符 --编码字符集--> 二进制
解码:二进制 --解码字符集--> 字符
byte[] data = "中国".getBytes("gbk");// 编码 char-->byte
String str = new String(data, "gbk");// 解码 byte-->char,与编码字符集统一,否则出现乱码
2)乱码
a.编码与解码的字符集不统一
b.字节缺少,长度丢失
3)转换流
a.输出流(写入),编码 OutputStreamWriter(OutputStream out, String charsetName);
b.输入流(读取),解码 InputStreamReader(InputStream in, String charsetName);
8. 使用
1)创建 src 或 dest
2)选择流
3)操作流
4)释放资源 close();
9. 控制台
1)键盘输入
Scanner sc = new Scanner(System.in);
2)文件输入
InputStream is = new BufferedInputStream(new FileInputStream(src)); Scanner sc = new Scanner(is);
3)输出到控制台
System.out.println("hello, world");
4)输出到指定文件
PrintStream ps = new PrintStream(new BufferedOutputStream(new FileOutputStream(dest))); ps.println("hello, world");
5)错误样式输出
System.err.println();
6)重定向
System.setIn(InputStream in);
System.setOut(PrintStream out);
System.setOut(new PrintStream(OutputStream out, boolean autoFlush)); System.out.println("控制台-->文件");
System.setErr(PrintStream err);
7)回到控制台:FileDescriptor.out
System.setOut(new PrintStream(FileDescriptor.out, boolean autoFlush)); System.out.println("控制台")
public class CopyDirectory {
//拷贝文件夹
public static void copyDir(File src, File dest){
if(src.isDirectory()){
//父类文件夹不能拷贝到子类中
if(dest.getAbsolutePath().contains(src.getAbsolutePath())){
return;
}
}
copyFileDetail(src, dest);
}
//拷贝细节
private static void copyFileDetail(File src, File dest) {
if(src.isFile()){//文件
copyFile(src, dest);
}else if(src.isDirectory()){//文件夹
dest.mkdirs();
//获取下一级文件|目录
for(File sub : src.listFiles()){
copyFileDetail(sub, new File(dest, sub.getName()));
}
}
}
private static void copyFile(File src, File dest) {
//2.选择流
InputStream is = null;
OutputStream os = null;
try {
is = new BufferedInputStream(new FileInputStream(src));
os = new BufferedOutputStream(new FileOutputStream(dest));
//3.文件拷贝 循环+读取+写出
byte[] bt = new byte[1024];
int len = 0;
while(-1!=(len=is.read(bt))){
os.write(bt, 0, len);
}
os.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
System.out.println("文件查找失败");
} catch (IOException e) {
e.printStackTrace();
System.out.println("文件拷贝失败");
} finally{
if(null!=is){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
System.out.println("文件关闭失败");
}
}
if(null!=os){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
System.out.println("文件关闭失败");
}
}
}
}
}
拷贝文件夹
public class Convert {
public static void main(String[] args) throws IOException {
//编码
BufferedWriter or = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(
new File("E:/test/a.txt")), "gbk"
)
);
String off = "转换流:字节流转为字符流";
or.write(off);
or.flush();
//解码
BufferedReader br = new BufferedReader(
new InputStreamReader(
new FileInputStream(
new File("E:/test/a.txt")), "gbk"
)
);
String info = null;
while(null!=(info=br.readLine())){
System.out.println(info);
}
}
}
转换流
public class SplitFile {
//文件名
private String fileName;
//文件路径
private String filePath;
//文件大小
private long length;
//块数
private int size;
//每一块的大小
private long blockSize;
//每块的名称
private List<String> blockPath;
public SplitFile(){
this.blockPath = new ArrayList<String>();
}
public SplitFile(String filePath){
this(filePath, 1024);
}
public SplitFile(String filePath,long blockSize){
this();
this.filePath = filePath;
this.blockSize = blockSize;
init();
}
private void init() {
File src = null;
src=new File(filePath);
//健壮性
if(null==filePath || !src.exists()){
return;
}
if(src.isDirectory()){
return;
}
//文件名
this.fileName = src.getName();
//计算块数,是实际大小,每块大小
this.length = src.length();
//修正最后一块大小
if(this.blockSize>length){
this.blockSize=length;
}
//确定块数
this.size = (int)Math.ceil(length*1.0/this.blockSize);
}
private void initPathName(String destPath){
for(int i=0;i<this.size;i++){
String original = this.fileName.substring(0, this.fileName.lastIndexOf("."));
String tail = this.fileName.substring(this.fileName.lastIndexOf("."));
this.blockPath.add(destPath+"/"+original+"_Part"+i+tail);
}
}
/**
* 文件分割
* @param destPath 分割文件的存放 目录
*/
public void split(String destPath){
//确定文件路径
initPathName(destPath);
long beginPos = 0;//起始点
long actualBlockSize = this.blockSize;//实际大小
//计算所有块的大小,位置,索引
for(int i=0; i<this.size; i++){
if(i==size-1){//最后一块
actualBlockSize = this.length - beginPos;
}
splitDetail(i, beginPos, actualBlockSize);
beginPos += actualBlockSize;
}
}
public void splitDetail(int index, long beginPos, long actualBlockSize){
//文件的拷贝
//1.创建源
File src = new File(this.filePath);//源文件
File dest = new File(this.blockPath.get(index));//目标文件
//2.选择流
RandomAccessFile raf = null;
BufferedOutputStream bos = null;
try {
raf = new RandomAccessFile(src, "r");
bos = new BufferedOutputStream(new FileOutputStream(dest));
//3.从指定位置开始读取文件
raf.seek(beginPos);
//缓冲区
byte[] bt = new byte[1024];
//接收长度
int len = 0;
while(-1!=(len=raf.read(bt))){
if(actualBlockSize-len>0){//如果每块的实际大小大于 1024 个字节数,则继续循环
bos.write(bt, 0, len);
actualBlockSize -= len;//剩余量
}else{//写出最后一次的剩余量
bos.write(bt, 0, (int)actualBlockSize);
break;
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
if(null!=raf && null!=bos){
try {
raf.close();
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 文件合并
*/
public void mergeFile(String destPath){
//创建源
File dest = new File(destPath);
//选择流
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
bos = new BufferedOutputStream(new FileOutputStream(dest,false));
for(int i=0;i<this.blockPath.size();i++){
bis = new BufferedInputStream(
new FileInputStream(new File(this.blockPath.get(i)))
);
//缓冲区
byte[] bt = new byte[1024];
//接收长度
int len = 0;
while(-1!=(len=bis.read(bt))){
bos.write(bt,0,len);
}
bos.flush();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
if(null!=bis && null!=bos){
try {
bis.close();
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 合并02
*/
public void mergeFile02(String destPath){
//1.创建源
File dest = new File(destPath);
//选择流
SequenceInputStream sis = null;//输入流
BufferedOutputStream bos = null;//输出流
//创建容器
Vector<InputStream> vi = new Vector<InputStream>();
try {
bos = new BufferedOutputStream(new FileOutputStream(dest,false));
for(int i=0;i<this.blockPath.size();i++){
vi.add(new BufferedInputStream(
new FileInputStream(new File(this.blockPath.get(i)))
));
}
sis = new SequenceInputStream(vi.elements());
//缓冲区
byte[] bt = new byte[1024];
//接收长度
int len = 0;
while(-1!=(len=sis.read(bt))){
bos.write(bt,0,len);
}
bos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
if(null!=sis && null!=bos){
try {
sis.close();
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* main
*/
public static void main(String[] args) {
SplitFile file = new SplitFile("E:/test/k.txt", 50);
System.out.println(file.size);
file.split("E:/test");
file.mergeFile("E:/test/k02.txt");
file.mergeFile02("E:/test/k03.txt");
}
}
文件分割
public class CloseUtil {
/**
* 工具类关闭流
* 可变参数: ... 只能在形参最后一个位置,处理方式和数组一致
* @param io
*/
public static void close(Closeable ...io){
for(Closeable temp:io){
if(null!=temp){
try {
temp.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 泛型方法的关闭流
* @param io
*/
public static<T extends Closeable> void closeAll(T ...io){
for(Closeable temp:io){
if(null!=temp){
try {
temp.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
关闭流