飞道的博客

三万字的java I/O流基础总结看完肯定能把女朋友教会

501人阅读  评论(0)



目录:
1.File类详解
2.I/O流概述
3.字节输出流(OutputStream)
4.字节输入流(InputStream)
5. 字符流概述
6.字符输入流(Reader)
7.字符输出流(Writer)
8.Properties类详解
9.缓冲流概述
10.字节缓冲流(BufferedInputStream,BufferedOutputStream)
11.字符缓冲流(BufferedReader,BufferedWriter)
12.缓冲流高效率测试
13.转换流概述
14. InputStreamReader类和 OutputStreamWriter类
15. 序列化
16.打印流

1.File类详解

(1)首先File的位置:java.io.File

(2)File的作用

1.File类是专门对文件进行操作的类,只能对文件本身进行操作,不能对文件内容进行操作
2.File类是文件目录路径名的抽象表示,主要用于文件和目录的创建、查找和删除等操作

(3)File类的构造方法

  1. public File(String pathname):通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。(说白了就是你给一个正确的字符串里边包含路径和文件名,然后按照这个路径和你给的文件名创建相应的File对象)
  2. public File(String parent, String child):从父路径名字符串和子路径名字符串创建新的 File实例。
  3. public File(File parent, String child):从父抽象路径名和子路径名字符串创建新的 File实例。

说着当然难受,上代码:

package untl1;
import java.io.File;
public class MyFile {
    public static void main(String[] args) {
        String str1="d:\\1\\a.txt";
        File file1=new File(str1);
        //运行结果创建一个为d:\\1\\a.txt的File对象

        String  str2="d:";
        String  str3="1\\a.txt";
        File   file2=new File(str2,str3);
        //运行结果创建一个为d:\\1\\a.txt的File对象
        
        String str4="d:";
        String str5="1\\a.txt";
        File  file3=new File(str4);
        File  file4=new File(file3,str5);
        //运行结果创建一个为d:\\1\\a.txt的File对象
        
    }
}

这里有几个注意点:

1.一个File对象代表硬盘中实际存在的一个文件或者目录
2.File类构造方法不会给你检验这个文件或文件夹是否真实存在,因此无论该路径下是否存在文件或者目录,都不影响File对象的创建
3.创建的是File流对象并不是已经在你的电脑磁盘上创建了相应的文件或者目录
4.你给的路径一定要已经存在,如果你想创建一个d:\a\b\c.txt的File流对象,那么a和b目录一定要已经存在,否则程序会抛出异常,因为系统找不到指定路径
5.如果你不指定路径,那么系统会默认把你想建的文件或者目录创建在本项目的路径下

(4)关于相对路径和绝对路径:

package untl1;
import java.io.File;
public class MyFile {
    public static void main(String[] args) {
        String str1="d:\\1\\a.txt";
        File file1=new File(str1);
        System.out.println(file1.getAbsolutePath());
        //运行结果:d:\1\a.txt

        File  file2=new File("b.txt");//这就是项目下的相对路径
        System.out.println(file2.getAbsolutePath());
        //运行结果:C:\Users\86166\IdeaProjects\until\b.txt
    }
}

这里有几点注意事项

1.路径不区分大小写
2.路径分隔符可以是两个反斜杠\\还可以是一个正斜杠/
3.相对路径是一个简化的路径,绝对路径是以盘符开头的路径

(4)File类的常用方法

方法名 作用
public String getAbsolutePath() 返回此File的绝对路径名字符串。
public String getPath() 将此File转换为路径名字符串。
public String getName() 返回由此File表示的文件或目录的名称。
public long length() 返回由此File表示的文件的长度。
public boolean exists() 此File表示的文件或目录是否实际存在。
public boolean isDirectory() 此File表示的是否为目录。
public boolean isFile() 此File表示的是否为文件。
public boolean createNewFile() 文件不存在,创建一个新的空文件并返回true,文件存在,不创建文件并返回false。
public boolean delete() 删除由此File表示的文件或目录。
public boolean mkdir() 创建由此File表示的目录。
public boolean mkdirs() 创建由此File表示的目录,包括任何必需但不存在的父目录。

关于常用方法的注意事项

1.我们创建File对象没有在磁盘上创建相应的文件和目录,在磁盘上创建用createNewFile()以及mkdir()与mkdirs()
2.如果此File表示目录,则目录必须为空才能用delete删除
3.mkdirs()和mkdir()方法类似,但mkdir(),只能创建一级目录,mkdirs()可以创建多级目录比如//a//b//c

(5)关于目录的遍历
先介绍两种方法:

public String[] list():返回一个String数组,表示该File目录中的所有子文件或目录。
public File[] listFiles():返回一个File数组,表示该File目录中的所有的子文件或目录。

下面用File[] listFiles()举个例子:

package untl1;
import java.io.File;
import java.io.IOException;
public class MyFile{
    public static void main(String[] args)throws IOException
    {
        File fp=new File("d:\\1");
        printF(fp);
    }
    static void printF(File fp)
    {
        System.out.println(fp.getName());
        if(fp.isDirectory())//如果判断它是一个目录
        {
            File arr[]=fp.listFiles();//返回所有的子目录和子文件
            for(File o:arr)//用for循环进行遍历
            {
                printF(o);
            }
        }
    }
}
//运行结果是把所有d:\\1目录下的所有文件和目录名打印出来

再使用File[] listFiles()的注意事项:

1.指定的目录必须存在
2.指定的必须是目录。否则容易引发返回数组为null,出现NullPointerException异常

2.I/O流概述

(1)I/O表述:
Java的IO流是实现输入/输出的基础,它可以方便地实现数据的输入/输出操作,在Java中把不同的输入/输出源(键盘、文件、网络连接等)抽象表述为“流”(stream),通过流的方式允许Java程序使用相同的方式来访问不同的输入输出源。 stream是从起源(source)到接收(sink)的有序数据。Java把所有传统的流类型(类或抽象类)都放在java.io包中,用以实现输入输出功能。

(2)I/O分类:
根据数据的流向分为:

1.输入流 :把数据从其他设备上读取到内存中的流。
2.输出流 :把数据从内存 中写出到其他设备上的流。

根据数据的类型分为:

1.输入流 :以字节为单位,读写数据的流。
2.输出流 :以字符为单位,读写数据的流。
字节流和字符流的操作方式几乎完全一样,区别只是操作的数据单元不同而已。字节
流操作的数据单元是字节,字符流操作的数据单元是字符,
Java中一个字符两个字节字节流适合读取视频,图片音频等,字符流适合读取纯文本文件我们还要必须明确一点的是,一切文件数据(文本、图片、视频等)在存储时,都是以二进制数字的形式保存,都一个一个的字节,那么传输时一样如此。所以,字节流可以传输任意文件数据。在操作流的时候,我们要时刻明确,无论使用什么样的流对象,底层传输的始终为二进制数据。

输入输出流都是相对于内存而言,从内存中出来就是输出,到内存中是输入

(3)四种流类型的祖先(都是继承Object类):

输入流 输出流
字节流 字节输入流 InputStream 字节输出流 OutputStream
字符流 字符输入流 Reader 字符输出流 Writer

(4)I/O流概念模型:


3.字节输出流(OutputStream)

1.关于OutputStream
所在位置:java.io.OutputStream
简介:字节输出流的所有类的超类

2.关于字节输出流的常用方法:

方法名 作用
public void close() 关闭此输出流并释放与此流相关联的任何系统资源。
public void flush() 刷新此输出流并强制任何缓冲的输出字节被写出。
public void write(byte[] b) 将 b.length个字节从指定的字节数组写入此输出流。
public void write(byte[] b, int off, int len) 从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。 也就是说从off个字节数开始读取一直到len个字节结束
public abstract void write(int b) 将指定的字节输出流。

以上五个方法则是字节输出流都具有的方法,由父类OutputStream定义提供,子类都会共享以上方法

3.FileOutputStream类
(1)FileOutputStream概述:
由于OutputStream是一个抽象类无法实例化对象,那么就需要OutputStream的子类,FileOutputStream是其的一个子类,文件输出流,用于把数据从内存写入到文件中

(2)FileOutputStream的构造方法:

  1. public FileOutputStream(File file):根据File对象为参数创建对象。
  2. public FileOutputStream(String name): 根据名称字符串为参数创建对象。

构造方法的作用:

  • 1.创建一个FileOutputStream的对象
  • 2.会根据构造方法传递的文件/文件路径,创建一个空的文件
  • 3.会把FileOutputStream的对象指向创建好的文件

(3)那么把数据写进文件的原理:
我们编写好的Java程序运行后,Java虚拟机会找操作系统,调用Windows写数据的方法,然后把数据写到文件中(由内存--------》写入磁盘)
java程序——》Jvm(虚拟机)——》OS(操作系统)——》OS调用写数据方法——》把数据写入文件中

(4)FileOutputStream的使用步骤:

1.创建一个FileOutputStream的对象,构造方法传递写入数据的目的地
2.调用FileOutputStream实例化对象write方法,把数据写入文件中
3.释放资源(流在使用的时候会占用一定的内存资源,使用后关闭会提高程序的效率)

write也分为三种写入方式:

1.public void write(int b):一个字节一个字节的写进文件
2.public void write(byte[] b):以一个字节数组的方式写进文件
3.public void write(byte[] b,int off,int len):写进以off索引开始len个字节

实例:

  package untl1;
import java.io.FileOutputStream;
import java.io.IOException;
public class MyFile{
    public static void main(String[] args) throws IOException {
        FileOutputStream  file1=new FileOutputStream("d:1\\a.txt");
        file1.write(97);
        file1.close();

        byte arr[]={98,99,100};
        FileOutputStream  file2=new FileOutputStream("d:1\\a.txt");
        file2.write(arr);
        file2.close();

        byte brr[]={101,102,103};
        FileOutputStream  file3=new FileOutputStream("d:1\\a.txt");
        file3.write(brr,1,2);
        file3.close();
    }
}

整个程序运行下来a.txt最终只会写进:fg
why?
首先看第一次写进,注意写数据的时候会把十进制的97转换成二进制,因为任意的文本编辑器(记事本等等)在打开的时候,都会查询编码表,把字节转换成字符表示

0~127:查询ASCII表
其他值:查询系统默认码表(中文GBK)这里有个地方需要注意,当我们第一个字节是负数,那么会和后边的一个字符组成中文显示比如{-1234,2234,-342,4233,534}就会前两个组成文字显示,第三个和第四个会组成汉字显示,由于第五个不是负数就会按照相应字符显示

所以第一次就只写进去一个字符a

那么该第二次写了,这里注意:在创建输出流对象的时候,如果你有这个文件,那么会清空文件里边的数据,如果没有就新建一个空白文件,所以第二次再写完后a.txt里边只有bcd三个字符

同理进行第三次写文件,最终只写进了fg

接下来认识一个String的方法:

getBytes():把字符串转换成字节数组

这样方便我们把字符串写进文件
例子:

package untl1;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
public class MyFile{
    public static void main(String[] args) throws IOException {
        FileOutputStream file1 = new FileOutputStream("d:1\\c.txt");
        String str="我想睡觉";
        byte  arr[]=str.getBytes();
        System.out.println(Arrays.toString(arr));//打印转换成字符串所对应的字节数组
        file1.write(arr);
        file1.close();
    }
}
运行结果:把我想睡觉写进了文件

(5)FileOutputStream实现数据追加续写、换行
上边讲了,每次创建流对象都会清空文件的数据,那么如何保留目标文件中数据,还能继续追加新数据呢?使用下边两个构造方法:

1、public FileOutputStream(File file, boolean append)
2、public FileOutputStream(String name, boolean append)

这两个构造方法,第二个参数中都需要传入一个boolean类型的值,true 表示追加数据,false 表示不追加也就是清空原有数据。这样创建的输出流对象,就可以指定是否追加续写了

在Windows系统中换行是\r\n
我们只需要把换行所代表的字符串写进文件,即可实现换行功能
例如:

package untl1;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
public class MyFile{
    public static void main(String[] args) throws IOException {
        FileOutputStream file1 = new FileOutputStream("d:1\\c.txt");
        byte  arr[]={97,98,99,100};
        System.out.println(Arrays.toString(arr));
      for (byte a:arr)
      {
          file1.write(a);
          file1.write("\r\n".getBytes());
      }
      file1.close();
    }
}
运行结果:
文件里边写进了:
a
b
c
d

4.字节输入流(InputStream)

1.关于InputStream
所在位置:java.io.InputStream
简介:字节输入流的所有类的超类

2.字节输入流的常用方法:

方法 作用
public void close() 关闭此输入流并释放与此流相关联的任何系统资源。
public abstract int read() 从输入流读取数据的下一个字节。
public int read(byte[] b) 该方法返回的int值代表的是读取了多少个字节,读到几个返回几个,读取不到返回-1

以上三个方法则是字节输入流都具有的方法,由父类InputStream定义提供,子类都会共享以上方法

3.FileInputStream类
(1)FileOutputStream概述:
由于InputStream是一个抽象类无法实例化对象,那么就需要InputStream的子类,FileOutputStream是其的一个子类,文件输入流,用于从文件种读取字节

(2)FileInputStream的构造方法

1、FileInputStream(File file): 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的 File对象 file命名。
2、FileInputStream(String name): 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名name命名。

构造方法的作用:

  • 1.创建一个FileInputStream流对象
  • 2.会把FileInputStream对象指定构造方法内的文件

(3)读取数据的原理:
我们编写好的Java程序运行后,Java虚拟机会找操作系统,调用Windows读取数据的方法,然后把数据写到文件中(由磁盘--------》读入内存)
java程序——》Jvm(虚拟机)——》OS(操作系统)——》OS调用写数据方法——》把数据写入文件中

(4)FileInputStream的使用步骤:

1.创建FileInputStream对象,构造方法中绑定要读取的数据
2.使用FileInputStream对象中的read方法,读取文件
3.释放资源

read的两种读取方式

  1. public int read():每次可以读取一个字节的数据,提升为int类型,读取到文件末尾,返回-1
  2. public int read(byte b[]):每次读取b的长度个字节到数组中,,返回读取到的有效字节个数,读取到末尾时,返回-1
    这里注意两种返回值不一样,第一种方法的返回值是读取的字节对应的int类型的值,而第二种方法的返回值是所读取的字节数
    每次读完文件指针会自动往后移动

实例:

这里先介绍String的两种构造方法:

1.public String(byte bytes[]):给定一个字节数组会把字节数组转换成字符串
2.public String(byte bytes[], int offset, int length):从下标offest开始读取length个字节并转换成字符串
这里的构造方法都有自动解码的功能,默认编码utf-8

package untl1;
import java.io.FileInputStream;
import java.io.IOException;
public class MyFile{
    public static void main(String[] args) throws IOException {
        FileInputStream  file1=new FileInputStream("d:/1/c.txt");
        int len=0;
        while( (len=file1.read())!=-1)
        {
            System.out.println((char)len);
        }


        FileInputStream  file2=new  FileInputStream("d:/1/c.txt");
        len=0;
        byte arr[]=new byte[2];
        while((len=file2.read(arr))!=-1)
        {
            System.out.println(new String(arr));
        }
        
    }
}

d:/1/c.txt文件内容:

运行结果:

(5)复制图片原理:

例子:

package untl1;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class MyFile {
    public static void main(String[] args) throws IOException {
        FileInputStream  file1= new FileInputStream("d:\\0.jpg");
        FileOutputStream file2= new FileOutputStream("d:1\\00.jpg");
        byte arr[] = new byte[1024];
        int len=0;
        while((len=file1.read(arr))!=-1)
        {
              file2.write(arr);
        }
        file1.close();
        file2.close();
    }
}
运行结果:
d盘下的0.jpg这张图片会被复制到d盘1目录下,且复制后在1目录下的图片名字为00.jpg

1.由于只创建一次输出流对象所以在写进文件的时候,写文件的指针自动后移,所以不必用追加写的方式创建FileOutputStream对象
2.FileInputStream和FileOutputStream由于都是对文件操作,所以指定的路径不能是目录

5.字符流概述

(1)我们在使用字节流的时候,可能会出现一些小问题,就是在遇到中文字符的时候,有时候读取的时候会显示乱码的问题,那是因为我们字节是一个一个读取,然而一个中文字符会占用几个字节,假如你一个汉字占用三个字节,你只读取了其中的两个字节,那么是不会显示汉字的,所以乱码就理所应当了。

尽管字节流也能有办法决绝乱码问题,但是还是比较麻烦,于是java就有了字符流,字符为单位读写数据,字符流专门用于处理文本文件。如果处理纯文本的数据优先考虑字符流,其他情况就只能用字节流了(图片、视频、等等只文本例外)。
从另一角度来说:字符流 = 字节流 + 编码表

字符流的继承关系:

6.字符输入流(Reader)

1.关于Reader
所在位置:java.io.Reader
简介:字符输入流的所有类的超类

2.字符输入流的常用方法:

方法名 方法作用
public void close() : 关闭此流并释放与此流相关联的任何系统资源
public int read() 从输入流读取一个字符
public int read(char[] cbuf) 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中

以上三个方法则是字符输入流都具有的方法,由父类Reader定义提供,子类都会共享以上方法

3.FileReader类
(1)FileReader类概述:
由于Reader是一个抽象类无法实例化对象,那么就需要Reader的子类,FileReader是其的一个子类,是读取字符文件的便利类,构造时使用系统默认的字符编码和默认字节缓冲区

(2)构造方法:

1.FileReader(File file): 创建一个新的 FileReader ,给定要读取的File对象
2.FileReader(String fileName): 创建一个新的 FileReader ,给定要读取的文件的字符串名称

(3)FileReader的使用:

类和FileInputStream类和FileReader用法完全类似包括两种read读取和String解码,只是读取的单位不同而已

例子:

package untl1;
import java.io.FileReader;
import java.io.IOException;
public class MyFile {
    public static void main(String[] args) throws IOException {
        FileReader  file1=new FileReader("d:1\\c.txt");
        int len;
        while((len=file1.read())!=-1)
        {
            System.out.println((char)len);
        }
        FileReader  file2=new FileReader("d:1\\c.txt");
        int lenn;
        char arr[]=new char[1024];//注意这里的字符串是char
        while((lenn=file2.read(arr))!=-1)
        {
            System.out.println(new String(arr));
            //这里得到new String是把字符数组转换成字符串,
            //也可以使用三个参数的,用法与前面的一样
        }
        file1.close();
        file2.close();
    }
}
运行结果:
谁
还
不
是
个
野
王
谁还不是个野王                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        

c.txt内容:

7.字符输出流(Writer)

1.关于Writer
所在位置:java.io.Writer
简介:是字符输入流的所有类的超类(父类),可以读取字符信息到内存中。它定义了字符输入流的基本共性功能方法。

2.字符输出流的常用方法:

方法名 作用
void write(int c) 写入单个字符
void write(char[] cbuf) 写入字符数组
abstract void write(char[] cbuf, int off, int len) 写入字符数组的某一部分,off数组的开始索引,len写的字符个数
void write(String str) 写入字符串
void write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数
void flush() 刷新该流的缓冲
void close() 关闭此流,但要先刷新它

以上七个方法则是字符输出流都具有的方法,由父类Writer定义提供,子类都会共享以上方法

3.FileWriter类
(1)FileWriter类概述:
由于Writer是一个抽象类无法实例化对象,那么就需要Writer的子类,FileWriter是其的一个子类,是写出字符到文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区

(2)构造方法:

1、FileWriter(File file): 创建一个新的 FileWriter,给定要读取的File对象。
2、FileWriter(String fileName): 创建一个新的 FileWriter,给定要读取的文件的名称。

(3)FileWriter的使用:
例子:

package untl1;
import java.io.FileWriter;
import java.io.IOException;
public class MyFile {
    public static void main(String[] args) throws IOException {
        FileWriter file1=new FileWriter("d:1\\c.txt");
        file1.write(98);
        file1.write("我是弟弟");
        file1.close();
    }
}
运行结果
c.txt里边写进:a我是弟弟

注意:关闭资源时,与FileOutputStream不同。 如果不关闭,数据只是保存到缓冲区,并未保存到文件。想要保存到缓冲区就必须关闭资源或者刷新该流的缓冲(就是flush方法)

(4)关闭close和刷新flush
两者的区别:

flush:刷新缓冲区,流对象可以继续使用。
close:先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。
flush()这个函数是清空的意思,用于清空缓冲区的数据流,进行流的操作时,数据先被读到内存中,然后再用数据写到文件中,那么当你数据读完时,我们如果这时调用close()方法关闭读写流,这时就可能造成数据丢失,为什么呢?因为,读入数据完成时不代表写入数据完成,一部分数据可能会留在缓存区中,这个时候flush()方法就格外重要了。即便是flush方法写出了数据,操作的最后还是要调用close方法,释放系统资源。

(5)FileWriter的续写和换行和前面的字节流续写和换行一样的

8. Properties类详解

(1)Properties概述
是一种java配置文件的类,java.util.Properties继承于Hashtable,来表示一个持久的属性集(所以自己也是一个集合)。它使用键值结构存储数据每个键及其对应值都是一个字符串

(2)Properties常用方法:

常用方法名 作用
public Object setProperty(String key, String value) 保存一对属性
public String getProperty(String key) 使用此属性列表中指定的键搜索属性值
public Set stringPropertyNames() 返回所有键的名称的Set集合

(3)Properties常用方法的使用实例:
例子1:

package untl1;
import java.util.Properties;
import java.util.Set;
public class MyProperties {
    public static void main(String[] args) {
        //创建Properties集合对象
        Properties myProperties=new Properties();
        //使用setProperty往集合里边添加元素
        myProperties.setProperty("刘备","170");
        myProperties.setProperty("关羽","180");
        myProperties.setProperty("张飞","175");
        //使用stringPropertyNames方法把Properties中的键值取出来,存储到Set集合里
        Set<String> set=myProperties.stringPropertyNames();
        for (String key:set)
        {
            //使用getProperty把键对应的值取出来
            String  value=myProperties.getProperty(key);
            System.out.println(key+"="+value);
        }
    }
}
运行结果:
刘备=170
关羽=180
张飞=175

(4)Properties类中store方法:

1.public void store(Writer writer, String comments)
2.public void store(OutputStream out, String comments)
这里注意用第一种store方法可以把集合里的中文写进去,但是第二种写入方式不能把集合里边的中文写进去,第二个参数用来解释保存文件是做什么的,不能使用中文,会参生乱码,默认为Unicode编码一般都传的是空字符串“”

方法的作用:把Properties集合里边的临时数据持久化写入磁盘中存储

使用步骤:

  • 1.创建Properties集合对象,添加数据
  • 2.创建字节/字符输出流对象,构造方法绑定要写进的目的地
  • 3.使用 Properties集合中的方法store把集合里边的临时数据持久化写入磁盘中存储
  • 4.释放资源
例子:
package untl1;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
public class MyProperties {
    public static void main(String[] args) throws IOException {
        Properties myProperties=new Properties();
        myProperties.setProperty("刘备","170");
        myProperties.setProperty("关羽","180");
        Object 张飞 = myProperties.setProperty("张飞", "175");
        FileWriter fw=new FileWriter("d:1\\c.txt");//c.txt是一个空白文件
        myProperties.store(fw,"");
        fw.close();
    }
}

运行结果(c.txt变化如下):

第一行是对写的东西进行解释,由于传进的是一个空的字符串所有没有内容
第二行是默认加的写入时间
之后就是集合里边的内容

(5)Properties类中load方法:

1.public void load(InputStream inStream)
2.public void load(Reader reader)
参数的解释:
InputStream inStream:字节输入流,不能读取含有中文的键值对
Reader reader:字符输入流,能读取含中文的键值对

使用步骤:

  • 1.创建Properties集合对象
  • 2.使用Properties集合对象中的load方法读取保存键值对的文件
  • 3.遍历集合

例子:

package untl1;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;
public class MyProperties {
    public static void main(String[] args) throws IOException {
        Properties myProperties=new Properties();
        FileReader file1=new FileReader("d:\\1\\c.txt");//里边保存第(4)点写进的内容
        myProperties.load(file1);
        Set<String> set=myProperties.stringPropertyNames();
        for (String key:set)
        {
            System.out.println(key+"="+myProperties.getProperty(key));
        }
    }
}
运行结果:
刘备=170
关羽=180
张飞=175

1.存储键值对的文件中,键与值的连接符号可以使用=,空格或者其他符号
2.存储文件中,可以使用#进行注解,注解的键值对不会被读取
3.存储价值对的文件中,键与值都是字符串不用加引号

9. 缓冲流概述

由于四个基本流(FileInputStream,FileOutputStream,FileReader,FileWriter)的效率比较低,体现在我们多次读写文件的时候都要对原始数据多次访问,每次对原始数据的访问都会有
java程序——》java虚拟机——》操作系统——》操作系统调用读写操作,显得太麻烦,缓冲流就是在第一次访问时就把要读或者要写的内容存在一个数组中(这个数组就是缓冲流的根本),那么当我们二次访问时候就可以直接在数组里进行操作

专业点来讲就是:缓冲流把数据从原始流成块读入或把数据积累到一个大数据块后再成批写出,通过减少通过资源的读写次数来加快程序的执行

字节缓冲流:BufferedInputStream,BufferedOutputStream
字符缓冲流:BufferedReader,BufferedWriter
是对四个基本流的加强版

再来看一下四种缓冲流的继承关系;

10.字节缓冲流(BufferedInputStream,BufferedOutputStream)

1.字节缓冲输出流(BufferedOutputStream)
(1)构造方法:

1.public BufferedOutputStream(OutputStream out) :创建一个新的缓冲输入流,注意参数类型为InputStream。
2.public BufferedOutputStream(OutputStream out,int size): 创建一个新的缓冲输出流,注意size就是自定义缓冲流的数组,不指定就是默认的大小

(2)使用步骤

  • 1.创建FileOutputStream对象,构造方法中绑定要输出的目的地
  • 2.创建BufferedOutputStream对象,构造方法为FileFileOutputStream对象,提高FileOutputStream的效率
  • 3.使用BufferedOutputStream对象的writer方法,把数据写入内部缓冲区里边
  • 4.使用BufferedOutputStream里边的flush方法,把内部缓冲区里边的数据刷新到文件里
  • 5.释放资源

例子:

package untl1;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class MyProperties {
    public static void main(String[] args)throws IOException {
        FileOutputStream file1=new FileOutputStream("d:1\\c.txt");//c.txt是空的文件
        BufferedOutputStream bos=new BufferedOutputStream(file1);
        String str="我是哥哥";
        byte arr[]=str.getBytes();
        bos.write(arr);
        bos.flush();
        bos.close();
    }
}
运行结果:
c.txt文件写进了我是哥哥

2.字节缓冲输入流(BufferedInputStream)
(1)构造方法:

1.public BufferedInputStream(InputStream in) :创建一个新的缓冲输入流,注意参数类型为InputStream
2.public BufferedInputStream(InputStream in,int size) ::创建一个新的缓冲输入流,size作用同上

(2)使用步骤:

  • 1.创建FileInputStream对象,构造方法中绑定要读取的数据源
  • 2.创建BufferedInputStream对象,构造方法中传递FileInputStream对象,提高FileInputStream对象的读取效率
  • 3.使用BufferedInputStream中的方法read方法读文件
  • 4.释放资源
例子:
package untl1;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
public class MyProperties {
    public static void main(String[] args)throws IOException {
        FileInputStream file1=new FileInputStream("d:1\\c.txt");//里边就一句话"我是哥哥"
        BufferedInputStream bis=new BufferedInputStream(file1);
        byte[]  arr=new byte[3];
        int len=0;
        while((len=bis.read(arr))!=-1)
        {
            System.out.println(new String(arr));
        }

    }
}
运行结果:
我
是
哥
哥

11.字符缓冲流(BufferedReader,BufferedWriter)

1.字符缓冲输出流
(1)构造方法:

1.public BufferedWriter(Writer out):创建一个新的缓冲输入流,注意参数类型为Reader
2.public BufferedWriter(Writer out,int sz):创建一个新的缓冲输入流,sz作用同上

(2)使用步骤:

  • 1.创建字符输出流对象,构造方法中传递字符输出流对象
  • 2.调用字符缓冲输出流的writer方法,把数据吸入内存缓冲区
  • 3.调用字符缓冲输出流的flush方法,把内存缓冲区的数据刷新到文件中
  • 4.释放资源

例子:

package untl1;
import java.io.*;
public class MyProperties {
    public static void main(String[] args)throws IOException {
        FileWriter fw=new FileWriter("d:1\\c.txt");
        BufferedWriter bf=new BufferedWriter(fw);
        String str="我是弟弟";
        bf.write(new String(str));
        bf.flush();
        bf.close();
    }
}
运行结果:
把我是弟弟写进c.txt文件

(3)BufferedWriter特有的方法

public void newLine(): 换行,由系统属性定义符号
我们以前写数据的时候把“\r\n”写进文件就会换行,但是这里可以直接调用这个方法就能实现换行

2.字符缓冲输入流
(1)构造方法:

1.public BufferedReader(Reader in):创建一个新的缓冲输入流,注意参数类型为Reader
2.public BufferedReader(Reader in,int sz):创建一个新的缓冲输入流,sz作用同上

(2)使用步骤:

  • 1.创建字符缓冲输入流对象,构造方法中传递字符输入流
  • 2.使用字符缓冲输入流对象的read方法读取文本
  • 3.释放资源
例子:
package untl1;
import java.io.*;
public class MyProperties {
    public static void main(String[] args)throws IOException {
       FileReader fr=new FileReader("d:1\\c.txt");//c.txt里只有一句话:我是弟弟
       BufferedReader bf=new BufferedReader(fr);
       char arr[]=new char[5];
       int len=0;
       while((len=bf.read(arr))!=-1)
       {
           System.out.println(new String(arr,0,len));
       }
       bf.close();
    }
}
运行结果:
我是弟弟

(3)BufferedReader特有的方法

public String readLine(): 读一行数据。 读取到最后返回null

例子:

package untl1;
import java.io.*;
public class MyProperties {
    public static void main(String[] args)throws IOException {
       FileReader fr=new FileReader("d:1\\c.txt");
       BufferedReader bf=new BufferedReader(fr);
       String str1=bf.readLine();
        System.out.println(str1);
        String str2=bf.readLine();
        System.out.println(str2);
    }
}
运行结果:
我是弟弟
null

12.缓冲流高效率测试

缓冲流有多高效呢,接下来我们来测试一下,博主把d:0.jpg复制到d:1\\0.copy.jpg,分别用普通流和缓冲流进行比较:
普通流:

package untl1;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class MyProperties {
    public static void main(String[] args)throws IOException {
        long begin=System.currentTimeMillis();
        FileInputStream fis=new FileInputStream("d:0.jpg");
        FileOutputStream fos=new FileOutputStream("d:1\\0copy.jpg");
        int len=0;
        while((len=fis.read())!=-1)
        {
            fos.write(len);
        }
        fos.close();
        fis.close();
        long  end=System.currentTimeMillis();
        System.out.println("整个过程耗时"+(end-begin)+"毫秒");
    }
}
运行结果:
整个过程耗时46毫秒

缓冲流:

package untl1;
import java.io.*;
public class MyProperties {
    public static void main(String[] args)throws IOException {
        long begin=System.currentTimeMillis();
        FileInputStream fis=new FileInputStream("d:0.jpg");
        FileOutputStream fos=new FileOutputStream("d:1\\0copy.jpg");
        BufferedInputStream bis=new BufferedInputStream(fis);
        BufferedOutputStream  bos=new BufferedOutputStream(fos);
        int  len=0;
        while((len=bis.read())!=-1)
        {
            bos.write(len);
        }
        bos.flush();
        bos.close();
        fis.close();
        long  end=System.currentTimeMillis();
        System.out.println("整个过程耗时"+(end-begin)+"毫秒");
    }
}
运行结果:
整个过程耗时3毫秒

结论:你品,你细品

13.转换流概述

(1)乱码问题:

在介绍转换流之前,不知道大家有没有遇到一个问题
使用FileReader或者OutputStream读取txt文件,明明写的代码是正确的但是却读到一堆乱码,.

例子:

```cpp
package untl1;
import java.io.FileReader;
import java.io.IOException;
public class MyFile {
    public static void main(String[] args) throws IOException {
        FileReader  file1=new FileReader("d:1\\c.txt");//里边是几个汉字
        int len;
        while((len=file1.read())!=-1)
        {
            System.out.println((char)len);
        }
        FileReader  file2=new FileReader("d:1\\c.txt");
        int lenn;
        char arr[]=new char[1024];
        while((lenn=file2.read(arr))!=-1)
        {
            System.out.println(new String(arr));
        }
        file1.close();
        file2.close();
    }
}
运行结果:
���

为啥呢,往下看

(2)字符编码和解码:

我们知道,计算机中储存的数据都是用二进制数表示的,而我们在屏幕上看到的数字、英文、标点符号、汉字等字符是二进制数转换之后的结果。按照某种规则,将字符存储到计算机中,称为编码 。反之,将存储在计算机中的二进制数按照某种规则解析显示出来,称为解码 。比如说,按照A规则存储,同样按照A规则解析,那么就能显示正确的文本符号。反之,按照A规则存储,再按照B规则解析,就会导致乱码现象。所以开头的问题就已经明确,当我们使用FileReader或者InputStream进行字符的读取的时候,解码时默认为utf-8,我们电脑txt文件默认编码用ASCII,所以我们只需要改变编码的方式为utf-8就能把汉字正确的读取出来(打开文件然后选择另存为就可以选择编码方式如下图)

编码和解码简单来说:

编码:字符(能看懂的)------》字节(看不懂的)
解码:字节(看不懂的)------》字符(能看懂的)

(3)字符编码和编码表

1.字符编码: 就是一套自然语言的字符与二进制数之间的对应规则。
2.z字符集(也叫编码表):是生活中文字和计算机中二进制的对应规则

字符集的分类:

字符集 字符集解析
ASCII字符集
  • ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,用于显示现代英语,主要包括控制字符(回车键、退格、换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号)。
  • 基本的ASCII字符集,使用7位(bits)表示一个字符,共128字符。ASCII的扩展字符集使用8位(bits)表示一个字符,共256字符,方便支持欧洲常用字符。
ISO-8859-1字符集:
  • 拉丁码表,别名Latin-1,用于显示欧洲使用的语言,包括荷兰、丹麦、德语、意大利语、西班牙语等
  • ISO-8859-1使用单字节编码,兼容ASCII编码
GBxxx字符集
  • GB就是国标的意思,是为了显示中文而设计的一套字符集
  • GB2312:简体中文码表。一个小于127的字符的意义与原来相同。但两个大于127的字符连在一起时,就表示一个汉字,这样大约可以组合了包含7000多个简体汉字,此外数学符号、罗马希腊的字母、日文的假名们都编进去了,连在ASCII里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的"全角"字符,而原来在127号以下的那些就叫"半角"字符了。
  • GBK:最常用的中文码表。是在GB2312标准基础上的扩展规范,使用了双字节编码方案,共收录了21003个汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等。
  • GB18030:最新的中文码表。收录汉字70244个,采用多字节编码,每个字可以由1个、2个或4个字节组成。支持中国国内少数民族的文字,同时支持繁体汉字以及日韩汉字等。
Unicode字符集
  • Unicode编码系统为表达任意语言的任意字符而设计,是业界的一种标准,也称为统一码、标准万国码
  • 它最多使用4个字节的数字来表达每个字母、符号,或者文字。有三种编码方案,UTF-8、UTF-16和UTF-32。最为常用的UTF-8编码。
  • UTF-8编码,可以用来表示Unicode标准中任何字符,它是电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。所以,我们开发Web应用,也要使用UTF-8编码。它使用一至四个字节为每个字符编码,编码规则:128个US-ASCII字符,只需一个字节编码。拉丁文等字符,需要二个字节编码。大部分常用字(含中文),使用三个字节编码。其他极少使用的Unicode辅助字符,使用四字节编码

14. InputStreamReader类和 OutputStreamWriter类

1.InputStreamReader类
(1) 转换流java.io.InputStreamReader,是Reader的子类,从字面意思可以看出它是从字节流到字符流的桥梁。它读取字节,并使用指定的字符集将其解码为字符。它的字符集可以由名称指定,也可以接受平台的默认字符集。
(2)构造方法:

1.InputStreamReader(InputStream in): 创建一个使用默认字符集的字符流。
2.InputStreamReader(InputStream in, String charsetName): 创建一个指定字符集的字符流。指定的字符集大小写不限

(3)使用步骤:

  • 1.创建InputStreamReader对象,构造方法中传递字节输入流和指定的编码表的名称
  • 2.使用InputStreamReader里边的read方法读取文件
  • 3.释放资源

例子:

package untl1;
import java.io.*;
public class MyProperties {
    public static void main(String[] args)throws IOException {
        FileInputStream  fis=new FileInputStream("d:1\\c.txt");
        InputStreamReader isr=new InputStreamReader(fis,"utf-8");
        int  len=0;
        while((len=isr.read())!=-1)
        {
            System.out.println((char)len);
        }
        isr.close();
    }
}
运行结果:
把c.txt文件里的内容按照utf-8标准解析出来

注意InputStreamReader构造方法传进的是字节输出流

2.OutputStreamWriter类
(1)转换流java.io.OutputStreamWriter ,是Writer的子类,字面看容易混淆会误以为是转为字符流,其实不然,OutputStreamWriter为从字符流到字节流的桥梁。使用指定的字符集将字符编码为字节。它的字符集可以由名称指定,也可以接受平台的默认字符集。

(2)构造方法:

1.OutputStreamWriter(OutputStream in): 创建一个使用默认字符集的字符流。
2.OutputStreamWriter(OutputStream in, String charsetName): 创建一个指定字符集的字符流。指定的字符集大小写不限

(3)使用步骤:

  • 1.创建OutputStreamWriter对象构造方法中传递字节输出流和指定的编码表名称
  • 2.使用OutputStreamWriter对象中的writer方法,把字符转换为字节存放在缓冲区
  • 3.使用OutputStreamWriter对象中的flush方法,把缓冲区的内容打印到文件上
  • 4.释放资源

例子:

package untl1;
import java.io.*;
public class MyProperties {
    public static void main(String[] args)throws IOException {
      FileOutputStream fos=new FileOutputStream("d:1\\c.txt");
      OutputStreamWriter  osw=new OutputStreamWriter(fos,"utf-8");
      String str="我是咯咯";
      osw.write(str);
      osw.flush();
      osw.close();
    }
}

注意OutputStreamWriter构造方法传进的是字节输入流

15.序列化

1.序列化概述
(1)序列化的含义和意义:
序列化机制允许将实现序列化的Java对象转换成字节序列,这些字节序列可以保存在
磁盘上,或通过网络传输,以备以后重新恢复成原来的对象。序列化机制使得对象可
以脱离程序的运行而独立存在。对象的序列化(Serialize)指将一个Java对象写入IO流中,与此对应的是,对象的反序列化(Deserialize)则指从IO流中恢复该Java对象如果需要让某个对象支持序列化
机制,则必须让它的类是可序列化的

(2)序列化和反序列化

序列化:Java 提供了一种对象序列化的机制用一个字节序列可以表示一个对象,该字节序列包含该对象的数据、对象的类型和对象中存储的属性等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。
反序列化:把字节序列还可以从文件中读取回来,重构对象,称为反序列化。对象的数据、对象的类型和对象中存储的数据信息,都可以用来在内存中创建对象。


2. ObjectOutputStream类
(1)java.io.ObjectOutputStream 类也叫对象的序列化流,将Java对象的原始数据类型写出到文件,实现对象的持久存储

虽然ObjectOutputStream是一个对象的序列化流,但是想要使一个对象序列化还要两个条件:

1.对象所属类类必须实现java.io.Serializable 接口(当实现此接口后,就会个给类添加一个标记,如果有的化可以进行序列化和反序列化操作,没有的话抛出异常)
2.对象所属类的所有属性必须是可序列化的。如果有一个属性不需要可序列化的,则该属性必须注明是瞬态的,使用transient 关键字修饰。静态成员(static)是不能被序列化的

(2)构造方法和特有的方法:

1.构造方法:public ObjectOutputStream(OutputStream out):构造方法传递字节输出流
2.特有的方法:void writeObject(Object obj):将指定的对象写入序列化流中

(3)ObjectOutputStream的使用步骤:

  • 1.创建ObjectOutputStream对象,构造方法传递字节输出流
  • 2.使用ObjectOutputStream对象中的writerObject方法,把对象写入文件
  • 3.释放资源
例子:
package untl1;
import java.io.*;
public class MyProperties {
    public static void main(String[] args) throws IOException{
        FileOutputStream  fos=new FileOutputStream("d:1\\c.txt");//c.txt是一个空白文档
        ObjectOutputStream  oos=new ObjectOutputStream(fos);
       perosn per=new perosn();
       oos.writeObject(per);
        oos.flush();
    }
}
class perosn   implements Serializable{
    private  int a;
    private  static int b=12;
    private transient int c;
    perosn()
    {
        this.a=10;
        b=100;
        this.c=1000;
    }
    public String toString()
    {
        System.out.println("a="+a);
        System.out.println("b="+b);
        System.out.println("c="+c);
        return "";
    }
}

3 . ObjectInputStream类

(1)java.io.ObjectInputStream反序列化流,将之前使用ObjectOutputStream序列化的原始数据恢复为对象。

(2)构造方法和特有的方法:

1.构造方法:public ObjectInputStream(InputStream in): 注意传递的是字节输入流
2.特有方法:public final Object readObject () : 读取一个对象。

(3)使用步骤:

  • 1.创建ObjectInputStream对象,构造方法传入字节输入流
  • 2.使用ObjectInputStream对象中的方法readObject读取保存对象的文件
  • 3.释放资源
  • 4.使用读取的对象

例子:

package untl1;
import java.io.*;
public class MyProperties {
    public static void main(String[] args) throws IOException,ClassNotFoundException{
        FileInputStream fis=new FileInputStream("d:1\\c.txt");//只有上一个例子写入的一个对象
        ObjectInputStream ois=new ObjectInputStream(fis);
        Object obj=ois.readObject();
        ois.close();
        System.out.println(obj);
    }
}
class perosn   implements Serializable{
    private  int a;
    private  static int b=12;
    private transient int c;
    perosn()
    {
        this.a=10;
        b=100;
        this.c=1000;
    }
    public String toString()
    {
        System.out.println("a="+a);
        System.out.println("b="+b);
        System.out.println("c="+c);
        return "";
    }
}
运行结果:
a=10
b=12
c=0

这个运行结果就印证了
如果有一个属性不需要可序列化的,则该属性必须注明是瞬态的,使用transient 关键字修饰。静态成员(static)是不能被序列化的

(4)注意事项:

1.对于JVM可以反序列化对象,它必须是能够找到class文件的类。如果找不到该类的class文件,则抛出一个 ClassNotFoundException 异常。
2.JVM反序列化对象时,能找到class文件,但是class文件在序列化对象之后发生了修改(就是在反序列化之前修改了类),那么反序列化操作也会失败,抛出一个InvalidClassException异常。

16.打印流

1.打印流概述:
平时我们在控制台打印输出,是调用print和println方法完成的,这两个方法都来自java.io.PrintStream类,该类能打印各种类型的值是一种便捷的输出方式,

2.PrintStream类

(1)构造方法:

public PrintStream(File file):输出的目的地是一个文件
public PrintStream(OutputStream out):输出的目的地是一个字节输出流
public PrintStream(String fileName):输出的目的地是一个文件路径

(2)PrintStream的特点:

1.只负责数据的输出,不负责数据的读取
2.与其他输入流不同·, PrintStream不会抛出IOException异常
3.有特有的方法print或println注意没有printf

(3)PrintStream的使用

1.PrintStream继承OutputStream
2.如果使用继承来自父类的write方法写数据那么写入数据的时候会查询码表
3.如果使用自己特有的方法print或者println方法写数据,则会原样输出

例子:

package untl1;
import java.io.FileNotFoundException;
import java.io.PrintStream;
public class MyProperties {
    public static void main(String[] args) throws FileNotFoundException {
        PrintStream ps=new PrintStream("D:1\\c.txt");//c.txt是空白文件
        ps.print(97);
        ps.write(97);
    }
}
运行结果:
在c.txt文件里的第一行内容为:a97

打印流还有更神奇的操作,那就是改变输出语句的目的地(打印流的流向)System.setOut方法改变输出语句的目的地为参数中传递的打印流的目的地

static void setOut(PrintStream our):重新分配标准输出流

例子:

package untl1;
import java.io.FileNotFoundException;
import java.io.PrintStream;
public class MyProperties {
    public static void main(String[] args) throws FileNotFoundException {
        PrintStream ps=new PrintStream("D:1\\c.txt");//c.txt是空文件
        System.out.println("heello  world");
        System.setOut(ps);
        System.out.println("哈哈哈");
    }
}
运行结果:
hello  world

哈哈哈则是被输出到c.txt文件中


转载:https://blog.csdn.net/qq_45737068/article/details/105610821
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场