IO流的介绍及应用

IO流

流的流向分类
分为Input输入流和Output输出流

流操作的数据

字符流:操作字符
只能操作普通文本文件
最常见的普通文本文件:.txt、java、.c、.cpp等其他语言的源代码
只要用文本工具(记事本、notepad++、editplus)可以打开的,而且打开后我们人类能看懂的都是文本文件
注意:我们用的.doc、excel、ppt这些不是文本文件

字节流:操作字节
能操作一切文件(文本文件、.mp3、视频、.avi、.rmvb、mp4、doc、excel、ppt)

java中的四大流

字符输入流:共同Reader  比如:FileReader,BufferedReader。功能:读取一个字符,读取一个字符数组。
字符输出流:共同Writer  比如:FileWriter,BufferedWriter。功能:写一个字符,写一个字符数组(一部分),写一个字符串。
字节输入流:共同父类InputSteam  比如:FileInputStream,BufferedInputStream。功能:读取一个字节,读取一个字节数组。
字节输出流:共同父类OutputStream  比如:FileOutputStream,BufferedOutputStream。功能:写一个字节,写一个字节数组(一部分)。

总结2条规律:
	只要是输入流,此流的方法名一定叫做read
	只要是输出流,此流的方法名一定叫做writer
	java中流的命名是十分规范的:
		功能+父类的名字	(FileOutputStream)

OutputStream:字节输出流的根类,这是一个抽象类

public void close();
public void flush();
//和写数据有关系的方法
public void write(int b);//写一个字节
public void write(byte[] bs);//写一个字节数组
public void write(byte[] bs, int startIndex, int length);//写一个字节数组的一部分

FileOutputStream:给文件中续写与换行问题
续写
以前用的构造:

public FileOutputStream(String filename);//默认就是不续写
public FileOutputStream(File file);//给定一个File对象,这个File对象代表我们要写入的文件

请用这个构造:

public FileOutputStream(String filename,boolean flag);
public FileOutputStream(File file,boolean flag);

换行
windows:\r\n
Linux:\n
Mac:\r

public static void main(String[] args) throws Exception{
        FileOutputStream fos = new FileOutputStream("1.txt",true);
        fos.write("\r\nhello".getBytes());
        fos.close();
}

InputStream:字节输入流的根类,这是一个抽象类

public int read();//读取一个字节,返回的是码值
public int read(byte[] bs);//读取一个字节数组,返回值表示实际读取到的字节数

读取一个字节

public static void main(String[] args) throws Exception{
    /**
     * 一、
     * 1、创建了文件字节输入流对象
     * 2、检测文件是否存在,如果不存在,直接抛出异常
     * 3、让fis输入流对象指向该文件
     */
    FileInputStream fis = new FileInputStream(new File("1.txt"));
    /**
     * 二、使用fis读取数据
     * 1、读取一个字节
     */
    int b = 0;
    while((b = fis.read()) != -1){
        System.out.print((char)b);
    }
    fis.close();
}

读取一个字节数组

public static void main(String[] args) throws Exception{
    /**
     * 一、
     * 1、创建了文件字节输入流对象
     * 2、检测文件是否存在,如果不存在,直接抛出异常
     * 3、让fis输入流对象指向该文件
     */
    FileInputStream fis = new FileInputStream(new File("1.txt"));
    /**
     * 二、使用fis读取数据
     * 1、读取一个字节
     */
//        int b = 0;
//        while((b = fis.read()) != -1){
//            System.out.println((char)b);
//        }
    //2、一次读取一个字节数组
    byte[] bs = new byte[4];
    int len = 0;
    while((len = fis.read(bs)) != -1){
        //System.out.println(len);
        //String类有一个构造public String(byte[], int startIndex, int len);
        System.out.print(new String(bs, 0, len));
    }
    fis.close();
}

复制文件
以字节方式读取

public static void main(String[] args) throws IOException {
    //1、源文件:是读取用的,new FileInputStream("源文件")
    FileInputStream fis = new FileInputStream("C:\\Users\\Hasee\\Pictures\\Saved Pictures\\yinyue3.jpg");
    FileOutputStream fos = new FileOutputStream("copy.jpg");
    //2、目标文件:是写入用的,new OutputStream("目标文件")
    //3、一边读取源文件,一边写出到目标文件
    long s = System.currentTimeMillis();
    int b = 0;
    while((b = fis.read()) != -1){
        fos.write(b);
    }
    long e = System.currentTimeMillis();
    System.out.println(e-s);
    //4、关闭流
    fos.close();
    fis.close();
}

以字节数组方式读取

public static void main(String[] args) throws IOException {
    //1、源文件:是读取用的,new FileInputStream("源文件")
    FileInputStream fis = new FileInputStream("C:\\Users\\Hasee\\Pictures\\Saved Pictures\\yinyue3.jpg");
    FileOutputStream fos = new FileOutputStream("copy.jpg");
    //2、目标文件:是写入用的,new OutputStream("目标文件")
    //3、一边读取源文件,一边写出到目标文件
    long s = System.currentTimeMillis();
    byte[] bs = new byte[1024];
    int len = 0;
    while((len = fis.read(bs)) != -1){
        fos.write(bs,0, len);
    }
    long e = System.currentTimeMillis();
    System.out.println(e-s);
    //4、关闭流
    fos.close();
    fis.close();
}

缓冲输出流

public static void main(String[] args) throws IOException {
    /**
     * 缓存流:相比没有缓冲区的流,效率更高
     * BufferedOutputStream 缓冲输出流
     *      构造方法摘要
     *      public BufferedOutputStream(OutputStream out)
     */
    //1、创建BufferedOutputStream对象
    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("1.txt"));
    //2、写数据
    //字节
//        bos.write(100);
    //字节数组
//        byte[] bs = "java".getBytes();
//        bos.write(bs);
    //字节数组的一部分
    bos.write("java".getBytes(), 0, 3);
    //3、关闭流
    bos.close();
}

缓冲输入流

public static void demo02() throws IOException {
    /**
     * BufferedInputStream 缓冲输入流
     *      构造方法摘要
     *      public BufferedInputStream(InputStream in)
     */
    //1、创建BufferedInputStream对象
    BufferedInputStream bis = new BufferedInputStream(new FileInputStream("1.txt"));
    //2、读取数据
//        int b = 0;
//        while((b = bis.read()) != -1){
//            System.out.print((char) b);
//        }
    byte[] bs = new byte[2];
    int len = 0;
    while ((len = bis.read(bs)) != -1){
        System.out.print(new String(bs, 0, len));
    }
    //3、关闭流
    bis.close();
}

复制单级文件夹

public static void demo03() throws IOException {
    /**
     * 复制单级文件夹:
     * 1、什么叫单级:一个文件夹中只有文件,没有其他文件夹
     * 2、复制文件夹,是没有一个专门的流的
     * 步骤:
     *      数据源:C:\Users\Hasee\Pictures\Saved Pictures\2017-09
     *      数据目的:F:\java学习笔记\demo
     */
    //1、定义源文件和目标文件
    File fileSrc = new File("C:\\Users\\Hasee\\Pictures\\Saved Pictures\\2017-09");
    File fileObj = new File("F:\\java学习笔记\\demo");
    //2、判断目标文件是否存在
    if(!fileObj.exists()){
        boolean b = fileObj.mkdir();
        if(b){
            System.out.println("目标文件夹不存在,成功创建一个!");
        }
    }else{
        System.out.println("目标文件夹已经存在,不需要创建,直接复制即可!");
    }
    //3、列出源文件下的所有文件对象
    File[] files = fileSrc.listFiles();
    //4、遍历files数组
    for(File file: files){
        //a.源文件:file对象
        //b.目标文件:file.getName()
        File obj = new File(fileObj, file.getName());
        System.out.println("源文件" + file);
        System.out.println("目标文件" + obj);
        //5、复制文件
        copyFile(file,obj);
    }
    System.out.println("文件夹" + fileSrc.getName() + "复制成功!");
}

private static void copyFile(File file1, File file2) throws IOException{
    //1、创建两个流对象
    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file1));
    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file2));
    //2、一边读取,一边写入
    byte[] bs = new byte[1024];
    int len = 0;
    while((len = bis.read(bs)) != -1){
        bos.write(bs, 0, len);
    }
    //3、关闭流
    bos.close();
    bis.close();
    System.out.println("复制文件" + file1.getName() + "成功!");
}

字节流读取中文出现的问题:

public static void demo04() throws IOException {
    //字节流写中文
    FileOutputStream fos = new FileOutputStream("ch.txt");
    fos.write("中国".getBytes());
    fos.close();
    //字节流读中文
    FileInputStream fis = new FileInputStream("ch.txt");
//        int b = fis.read();
//        System.out.println((char)b);//一个中文是两个字节,一个一个字节读会有问题
    byte[] bs = new byte[2];
    int len = 0;
    len = fis.read(bs);
    System.out.println(len);
    System.out.println(new String(bs, 0, len));//一个一个字节数组读取,可能也会出现乱码(中aa国)
}

解决方案:
a.字符流
b.转换流

字符编码表(字符集):
ASCII码表,老美发明的,保存了数组、字母,以及一些符号对应的数字,每一个字符都是一个字节 A-65 a-97 0-48。 0xxx xxxx
GB2312码表,保存常用的汉字(6000-7000个),一个中文占两个字节,而且这两个字节都是负数。1111 1010 1010 1101
GBK码表:保存了基本所有的汉字(20000多个),不管是英文中文还是符号,都是两个字节,第一个是负数,第二个可能是正数也可能是负数。
Unicode,统一码表(万国码表),不管是英文中文还是其他符号,都是两个字节。对于一些只需要一个字节表示的符号,会显得很浪费。
UTF-8码表,基于unicode,一个字节就可以存储的数据,不用两个字节存储,而且这个码表更加标准化,在每一个字节头加入了编码信息(后期到api中查找)。
结论:在GBK码表中一个中文2个字节 在UTF-8中一个中文3个字节。对于我们来说,用到的中文码表:GBK、UTF-8。
ISO-8859-1:拉丁码表,Tomcat。
GB18030:最新的中文码表,目前还没有正式使用。

编码:把具体文字–>对应码值

解码:把码值–>翻译成具体文字

OutputStreamWriter

/**
 * OutputStreamWriter:他是一个字符流
 *      extends Writer
 *      方法:写一个字符/字符数组(一部分)/字符串(一部分)
 * 描述:OutputStreamWriter是字符通向字节流的桥梁,查码表(编码)
 * OutputStreamWriter的构造:
 *      public OutputStreamWriter(OutputStream out)
 */
public class OutputStreamWriterDemo {
    public static void main(String[] args) throws IOException {
        //1、创建OutputStreamWriter对象
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("1.txt"));
        //2、osw写数据
        osw.write("中国");
        //3、关闭流
        osw.close();
    }
}

InputStreamReader

/**
 * InputStreamReader: 字符流
 *      extends Reader
 *      方法:一次读取一个字符,一次读取一个字符数组
 * InputStreamReader 是字节流通向字符流的桥梁,查码表
 * InputStreamReader的构造:
 *      public InputStreamReader(InputStream in)  //默认查GBK码表
 *      public InputStreamReader(InputStream in, String charsetName)  //查指定码表
 */
public class InputStreamReaderDemo {
    public static void main(String[] args) throws IOException {
        //1、创建InputStreamReader对象
//        InputStreamReader isr = new InputStreamReader(new FileInputStream("1.txt"));
        InputStreamReader isr = new InputStreamReader(new FileInputStream("1.txt"),"UTF-8");
        //2、读取数据
        int ch = isr.read();
        System.out.println((char)ch);
        ch = isr.read();
        System.out.println((char)ch);
        //3、关闭
        isr.close();
    }
}

序列化与反序列化(多用于安卓开发,例如保存游戏信息)

/**
 * 序列化流:写对象到文件
 *         ObjectOutputStream
 * 反序列化流:从文件中获取对象
 *         ObjectInputStream
 *
 *  ObjectOutputStream:对象的字节输出流,写对象
 * 构造:
 *      public ObjectOutputStream(OutputStream out)
 * 方法:
 *      public void writeObject(Object obj)
 *
 * ObjectInputStream:对象的字节输入流,读对象
 * 构造:
 *      public ObjectInputStream(InputStream in)
 * 方法:
 *      public Object readObject()
 */
public class ObjectStreamDemo {
    public static void main(String[] args) throws Exception {
        writeDog();
        readDog();
    }

    public static void readDog() throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("1.txt"));
        System.out.println(ois.readObject());
        ois.close();
    }

    public static void writeDog() throws IOException{
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("1.txt"));
        Dog dog = new Dog("张三",18);
        oos.writeObject(dog);//若Dog类没实现Serilizable,抛出NotSerializableException异常
        oos.close();
    }
}

java.io.Serializable接口中没有方法,用于标记作用,如果一个类有标记,可以序列化,没有标记就不能序列化
InvalidClassException:无效类异常
当写完一个对象之后,修改该对象所属的类,那么再次读取对象的时候,原来的类失效,会出现无效类异常。jvm通过版本号判断一个类是否被修改。加上

private static final long serialVersionUID = 1L;

可解决。

transient:关键字的作用
用来修饰成员变量,在序列化的时候,如果一个成员变量被transient修饰,那么序列化的时候会忽略该成员变量

打印流:打印数据
PrintWriter:打印字符流
PriterStream:打印字节流
方法都一样,区别在于打印的目的地不一样
PrintWriter:可以打印的目的地:
1、字符串的文件名;2、File对象;3、其他的OutputStream流;4、其他的Writer流。
PriterStream:可以打印的目的地:
1、字符串的文件名;2、File对象;3、其他的OutputStream流。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值