Java基础——I/O流简介(待续)

本文介绍了Java中的I/O流,包括字符流和字节流的分类,以及File类的使用。字符流基于字节流,能指定编码处理文字数据,避免乱码问题。字节流适用于处理非文本数据,如图片。文章还讲解了I/O流的常用基类,如InputStream、OutputStream、Reader、Writer,并展示了如何使用缓冲区提高读写效率。此外,提到了转换流用于在字节流和字符流之间转换,以及File类的方法,用于操作文件属性。
摘要由CSDN通过智能技术生成

IO流用来处理设备之间的数据传输。

  • 流按流向分为:输入流、输出流。
    输入流、输出流相对于内存设备而言。将外设中的数据读取到内存:输入;将内存的数据写入到外设中:输出。
  • 流按操作数据不同分为两种:字节流、字符流

字节流:通用流。
字符流:基于字节流。由来:字节流读取文字字节数据后,不直接操作而是先查指定的编码表,获取对应的数字,在对该文字进行操作。
ASCII:英文编码表
GB2312/GBK:中文编码表
UTF-8:国际通用码表
如果对一台计算机使用GBK编码存储,那么另一台UTF-8的机器无法识别正确的文字,并显示乱码。因此,字符流可以指定编码方式来获取对应的文字。

二、I/O流常用基类

字符流

字节流的抽象基类:InputStream,OutputStream
字符流的抽象基类:Reader,Writer
P.S. 有着四个类派生出的子类名称都是以其父类名作为子类名的后缀。如InputStream的子类FileInputStream,如Reader的子类FileReader。

需求:将一些文字存储到硬盘一个文件中。
注意:如果要操作文字数据,建议优先考虑字符流。使用FileWriter。

import java.io.*;
class FileWriterDemo throws IOException {
    public static void main(String[] args) {
        //该文件会被创建到指定目录下。如果文件存在,则会被覆盖。
        FileWriter fw = new FileWriter("demo.txt");
        //将数据写入到临时存储缓冲区中
        fw.write("abcde");
        //刷新该流的缓冲,将临时存放的数据写入到目的地
        //如果不写,则要等到缓冲区满才会写入目的地
        fw.flush();
        //关闭流,关闭资源,释放内存
        fw.close();
    }
}

I/O异常处理

import java.io.*
class FileWriterDemo2 {
    public static void main(String[] args) {
        FileWriter fw = null;
        try {
            fw = new FileWriter("demo.txt");
            fw.write("abcdefg");
        } catch(IOException e) {
            System.out.println("catch:" + e.toString());
        } finally {
            try {
                if(fw != null)
                    fw.close();
            } catch(IOException e) {
                System.out.println(e.toString());
            }
        }
    }
}

对已有文件的数据续写

import java.io.*
class FileWriterDemo3 {
    public static void main(String[] args) {
        FileWriter fw = null;
        try {
            //true参数,代表不覆盖已有的文件,在已有文件的末尾处进行数据读写
            fw = new FileWriter("demo.txt", true);
            fw.write("hello\r\n"thanks); //记事本中按\r\n换行
        } catch (IOException e) {
            System.out.println("catch:" + e.toString());
        } finally {
            try {
                if(fw != null)
                    fw.close();
            } catch(IOException e) {
                System.out.println(e.toString());
            }
        }           
    }
}

需求:读取一个文件,将读取到的字符打印到控制台。
第一种读取方式:read()方法读取文本文件数据

import java.io.*
public class FileReaderDemo {
    public static void main(String[] args) throws IOException {
        //创建一个文件读取流对象
        //如果文件不存在,会抛出FileNotFountException
        FileReader fr = new FileReader("demo.txt");
        //调用读取流对象的read()方法
        //read():一次读一个字符,而且会自动往下读。如果已到达流的末尾,则返回-1
        int ch = 0;
        while((ch = fr.read()) != -1) {
            System.out.println((char)ch);
        }
        fr.close;
    }
}

第二种读取方式:使用read(char[])读取文本文件数据

import java.io.*
public class FileReaderDemo2 {
    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader("demo.txt");
        char[] buf = new char[1024];
        int num = 0;
        while((num = fr.read(buf)) != -1) {
            System.out.println(new String(buf,0,num));
        }
        fr.close;
    }
}

打印一个.java文件,并打印在控制台上

import java.io.*
class FileReaderTest throws IOException {
    public static void main(String[] args) {
        FileReader fr = new FileReader("DateDemo.java");
        char[] buf = new char[1024];
        int num = 0;
        while((num = fr.read(buf)) != -1) {
            System.out.println(new String(buf,0,num));
        }
        fr.close();
    }
}

将C盘一个文本文件复制到D盘
复制的原理:将C盘下的文件数据存储到D盘的一个文件中。
步骤:
1、在D盘创建一个文件,用于存储C盘文件的数据
2、定义读取流和C盘文件关联
3、通过不断读写完成数据存储
4、关闭资源

import java.io.*
class CopyText throws IOException {
    public static void main(String[] args) {
        FileWriter fw = null;
        FileReader fr = null;
        try {
            fw = new FileWriter("D:\\SystemDemo_copy.txt");
            fr = new FileReader("C:\\SystemDemo.java");

            char[] buf = new char[1024];

            int len = 0;
            while((len=fr.read(buf)) != -1) {
                fw.write(buf,0,len);
            }
        } catch (IOException e) {
            throw new RuntimeException("读写失败");
        } finally {
            if(fr != null) {
                try {
                    fr.close();
                } catch(IOException e) {
                    e.printStackTrace();
                } 
            }
            if(fw != null) {
                try {
                    fw.close();
                } catch(IOException e) {
                    e.printStackTrace();
                } 
            }
        }
    }
}

字符流的缓冲区
缓冲区的出现提高了对数据的读写效率。
对应的类:BufferedWriter,BufferedReader

写入缓冲区

FileWriter fw = new FileWriter("buf.txt");
BufferedWriter bw = new BufferedWriter(fw);
for(int i=1; i<5; i++) {
    bw.write("abcd" + x);
    bw.newLine(); //跨平台的换行符
    bw.flush(); //只要用到缓冲区,就要刷新
}
//关闭缓冲区,就是在关闭缓冲区中的流对象,故不需要写fw.close()
bw.close(); 

读取缓冲区

FileReader fr = new FileReader("buf.txt");
BufferedReader br = new BufferedReader(fr);
String line = null;
while((line = br.readLine()) != null) {
    System.out.println(line);
}
br.close();

使用缓冲区复制文本文件

BufferedReader br = null;
BufferedWriter bw = null;
try {
    br = new BufferedReader(new FileReader("xxx.java"));
    bw = new BufferedWriter(new FileWriter("xxx_copy.txt"));
    String line = null;
    while((len = br.readLine()) != null) {
        bw.write(line);
        bw.newLine(); //readLine方法返回时,只返回回车符之前的数据内容,并不返回回车符,故要加上newLine()
        bw.flush();
    }
} catch (IOException e) {
    throw new RuntimeException("读写失败");
} finally {
    try {
        if(br != null) {
            br.close();
        } catch(IOException e) {
            throw new RuntimeException("读取关闭失败");
        }
    }
    try {
        if(bw != null) {
            bw.close();
        } catch(IOException e) {
            throw new RuntimeException("写入关闭失败");
        }
    }
}

写入换行使用BufferedWriter类中的newLine()方法。
读取一行数据使用BufferedReader类中的readLine()方法。

原理: 使用了读取缓冲区的read方法, 将读取到的字符进行缓冲并判断换行标记, 将标记前的缓冲数据变成字符串返回。

字节流

基本操作与字符流类相同。但它不仅可以操作字符,还可以操作其它媒体文件。
InputStream,OutputStream

需求:操作图片数据

public static void writeFile throws IOException() {
    FileOutputStream fos = new FileOutputStream("fos.txt");
    //数据直接写到了目的地中
    fos.write("abcde".getBytes());
    //字节流不需要刷新
    fos.close();
}

public static void writeFile throws IOException() {
    FileInputStream fis = new FileInputStream("xxx.txt");
    byte[] buf = new byte[1024];
    int len = 0;
    while((len = fis.read(buf)) != -1) {
        System.out.println(new String(buf,0,len));
    }
    fis.close();
}

复制一个图片
思路:
1、用字节流读取对象和图片关联
2、用字节写入流对象创建一个图片文件,用于存储获取到的图片数据
3、通过循环读写,完成数据的存储
4、关闭资源

class CopyPic {
    public static void main(String[] args) {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            fis = new FileInputStream("c:\\1.bmp");
            fos = new FileOutputStream("c:\\2.bmp");
            byte[] buf = new byte[1024];
            int len = 0;
            while((len = fis.read(buf)) != -1) {
                fos.write(buf,0,len);
            }
        } catch(IOException e) {
            throw new RuntimeException("复制文件失败");
        } finally {
            try {
                if(fis != null)
                    fis.close();
            } catch (IOException e){
                throw new RuntimeException("读取关闭失败");
            }
            try {
                if(fos != null)
                    fos.close();
            } catch (IOException e){
                throw new RuntimeException("写入关闭失败");
            }
        }
    }
}

演示MP3的复制,通过缓冲区
BufferedOutputStream
BufferedInputStream

BufferedInputStream bis = new BufferedInputStream(new FileInputStream("c:\\0.mp3"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("c:\\1.mp3"));
int by = 0;
while((by = bis.read()) != -1) {
    bos.write(by);
}
bos.close();
bis.close();

转换流
InputStreamReader
字节流通向字符流的桥梁。解码。在构造时接受一个字节流。

读取转换流:
需求:当录入一行数据后,就将该行数据进行打印。如果录入的数据是over,那么停止录入。

//获取键盘录入对象
InputStream in = System.in;
//将字节流转换成字符流对象
InputStreamReader isr = new InputStreamReader(in);
//为了提高效率,将字符串进行缓冲区技术高效操作,使用BufferedReader
BufferedReader br = new BufferedReader(isr);
String line = null;
while((line = br.readLine()) != null) {
    if("over".equals(line))
        break;  
    System.out.println(line.toUpperCase());
}
br.close();

写入转换流:
OutputStreamWriter
字符通向字节的桥梁。编码。在构造时接收一个输出流。

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
String line = null;
while((line = br.readLine()) != null) {
    if("over".equals(line))
        break;
    bw.write(line.toUpperCase());
    bw.newLine();
    bw.flush(); //务必写上
}
br.close();

需求:将键盘录入的数据写入到一个文件中。

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("out.txt")));
String line = null;
while((line = br.readLine()) != null) {
    if("over".equals(line))
        break;
    bw.write(line.toUpperCase());
    bw.newLine();
    bw.flush();
}

需求:将一个文件的数据打印在控制台上。

BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("xxx.java")));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
String line = null;
while((line = br.readLine()) != null) {
    if("over".equals(line))
        break;
    bw.write(line.toUpperCase());
    bw.newLine();
    bw.flush();
}

流操作的基本规律
通过两个明确来完成流对象的选择:
1、明确源和目的。
源:输入流 – InputStream Reader
目的:输出流 – OutputStream Writer
2、操作的数据是否是纯文本。
是:字符流
不是:字节流
3、当体系明确后,再明确使用哪个具体的对象。通过设备来进行区分。
源设备:内存、硬盘、键盘
目的设备:内存、硬盘、控制台

需求1:复制一个文本文件
源:InputStream / Reader
是否操作文本文件?是。选择Reader。
接下来明确要使用该体系中的哪个对象。
明确设备:硬盘上的文件
Reader体系中可以操作文件的对象是FileReader
是否需要提高效率?是。加入Reader体系中的缓冲区BufferedReader
FileReader fr = new FileReader(“a.txt”);
BufferedReader br = new BufferedReader(fr);

目的:OutputStream / Writer
是否纯文本:是。选择Writer
设备:硬盘上的文件
Writer体系中可以操作文件的对象是FileWriter.
是否需要提高效率?是。加入Writer体系中的缓冲区BufferedWriter
FileWriter fw = new FileWriter(“b.txt”);
BufferedWriter bw = new BufferedWriter(fw);

File类

用来将文件或文件夹封装成对象的类,可以操作文件与文件夹的属性信息。File对象可以作为参数传递给流的构造函数。
流只能操作数据,如果要操作数据的文件对象,必须用到File对象。

File常用方法:
1、获取
文件名称getName()
文件路径getPath(),getAbsolutePath
文件大小length()
文件修改时间lastModified()
2、创建和删除
创建 boolean createNewFile()
删除 delete()
3、判断
是否可执行 canExcecute()
是否可读 canRead()
是否可写 canWrite()
是否存在 exists()
是否是文件 isFile()
是否是目录 isDirectory()

打印流:该流提供了打印方法,可以将各种数据类型的数据都原样打印。
字节打印流:PrintStream
构造函数可以接受的参数类型:
1、file对象。File
2、字符串路径。String
3、字节输出流。OutputStream
PrintStream永远不会抛出IOException

字符打印流:PrintWriter
构造函数可以接受的参数类型:
1、file对象。File
2、字符串路径。String
3、字节输出流。OutputStream
4、字符输出流。Writer

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("a.txt"), true)); //可以自动刷新
String line = null
while((line = br.readLine()) != null) {
    if("over".equals(line))
        break;
    out.println(line.toUpperCase());
    //out.flush();
}
out.close();
br.close();

序列流SequenceInputStream
对多个流进行合并。

Vector<FileInputStream> v = new Vector<FileInputStream>();
v.add(new FileInputStream("c:\\1.txt"));
v.add(new FileInputStream("c:\\2.txt"));
v.add(new FileInputStream("c:\\3.txt"));
Enumeration<FileInputStream> en = v.elements();
SequenceInputStream sis = new SequenceInputStream(en);

FileOutputStream fos = new FileOutputStream("c:\\4.txt");
byte[] buf = new byte[1024];
int len = 0;
while((len = sis.read(buf)) != -1) {
    fos.write(buf,0,len);
}
fos.close();
sis.close();

切割流

public static void merge() {
    ArrayList<FileInputStream> a1 = new ArrayList<FileInputStream>();
    for(int x=1; x<=3; x++) {

    }
}

public static void splitFile() throws IOException {
    FileInputStream fis = new FileInputStream("c:\\1.bmp");
    FileOutputStream fos = null;

    byte[] buf = new byte[1024*1024];
    int len = 0;
    int count = 1;
    while((len = fis.read(buf)) != -1) {
        fos = new FileOutputStream("c:\\splitfiles\\"+(count++)".part");
        fos.write(buf,0,len);
        fos.close();
    }
    fis.close();
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值