IO流

一、IO流的分类

我们必须明确一点的是,一切文件数据(文本、图片、视频等)在存储时,都是以二进制数字的形式保存,都一个一个的字节,那么传输时一样如此。所以,字节流可以传输任意文件数据。在操作流的时候,我们要时刻明确,无论使用什么样的流对象,底层传输的始终为二进制数据

Ⅰ按流的方向

①输入流:数据从别的地方(文件、网络等)输入到我们写的程序中,即的过程;
②输出流:数据从我们的程序中输出到别的地方(本地文件),即的过程。

此输入、输出是相对于我们写的代码程序而言。

Ⅱ按数据单位

①字节流:以字节为传输单位,每次读、写一个字节。
②字符流:以字符为传输单位,每次读、写两个字符。

(1字符 = 2字节 、 1字节(byte) = 8位(bit) 、
一个汉字占两个字节长度,所以当有汉字时应该用字符流,使用字节流会出现乱码)

所有的流都是由以下四个抽象类派生出来的:
字节流:InputStream(字节输入流)、OutputStream(字节输入流)
字符流:Reader(字符输入流)、Writer(字符输出流)

Ⅲ按功能

①节点流:从向一个特定的地方(节点)读写数据。如FileInputStream。

②处理流:是对一个已存在的流的连接封装,通过所封装的流的功能调用实现数据读写。如BufferedReader。处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装。

处理流分类:
需要转换—— 转换流 InputStreamReader 、OutputStreamWriter
需要高效——缓冲流Bufferedxxx
多个源—— 序列流 SequenceInputStream
对象序列化——ObjectInputStream、ObjectOutputStream
保证数据的输出形式—— 打印流PrintStream、Printwriter
操作基本数据,保证字节原样性——DataOutputStream、DataInputStream

使用流时的步骤
1、首先选择输入流还是输出流;
2、然后考虑你传输数据时,是选择使用字节流传输还是字符流,有中文就选择字符流。
3、前面两步就可以选出一个合适的节点流,如果需要在此基础上增强功能,那么就在处理流中选择一个合适的即可。

二、IO流特性

①先进先出,最先写入输出流的数据最先被输入流读取到。

②顺序存取,不能随机访问中间的数据。

RandomAccessFile(随机文件操作):一个独立的类,直接继承至Object,可以从文件的任意位置进行存取(输入输出)操作。

③只读或只写,每个流只能是输入流或输出流的一种,不能同时具备两个功能,输入流只能进行读操作,对输出流只能进行写操作。在一个数据传输通道中,如果既要写入数据,又要读取数据,则要分别提供两个流。

三、File文件类

File类是对文件系统中文件以及文件夹进行封装的对象,可以操作文件和文件夹。在与流的相互应用是很频繁的;

ⅠFile构造方法

public File(String pathname) :通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。
public File(String parent, String child) :从父路径名字符串和子路径名字符串创建新的 File实例。
public File(File parent, String child) :从父抽象路径名子路径名字符串创建新的 File实例。

①直接指定全路径
File file= new File("file.txt");/若没有指定路径,则默认父目录为该项目
File file1= new File("D://first.txt");

②分别指定路径和文件名
File file2 = new File("D://dir1/dir2", "two.txt");

③分别创建路径文件夹和文件名称字符串,再new一个File
File dir = new File("D://dir1/dir2");/创建文件夹对象
String fileName = new String("three.txt");
File file3=new File(dir,fileName);
绝对路径:一个完整的路径,以盘符开头,例如F://aaa.txt
相对路径:一个简化的路径,不以盘符开头,例如//aaa.txt//b.txt

windows中的文件分隔符是 */都可以(优先使用/
但是在
Linux
中,文件分隔符只能是
*/** 所以用了\的程序在Linux下会出问题。
而**File.separator**是系统默认的文件分割符号,屏蔽了这些系统的区别,用File.separator保证了在任何系统下不会出错。

ⅡFile创建方法

public boolean createNewFile() :文件不存在,创建一个新的空文件并返回true,文件存在,不创建文件并返回false。
public boolean mkdir() :创建由此File表示的目录。(一级)
public boolean mkdirs() :创建由此File表示的目录,如果父文件夹不存在,会帮你创建出来(多级)

其中,mkdirs()和mkdir()方法类似,但mkdir(),只能创建一级目录,mkdirs()可以创建多级目录比如//a//b//c,所以开发中一般用mkdirs()

public static void main(String[] args) throws IOException {
    File file1= new File("file1.txt");/创建文件对象
    System.out.println(file1.createNewFile());/创建文件

    File dir=new File("dir1");/单级目录
    System.out.println(dir.mkdir());
    
    File dir2=new File("dir1/dir2");/多级目录
    System.out.println(dir2.mkdirs());
}
Ⅲ删除方法

public boolean delete():删除此抽象路径名表示的文件或目录

如果要删除一个文件夹,则所给文件夹必须为空才可删除【即该文件夹内不能包括文件或文件夹】。
在Eclipse中创建文件或文件夹时,如果忘记写盘符,在默认是在项目路径下创建。 Java中File对象的删除不走回收站,直接删除。

Ⅳ判断方法

public boolean renameTo(File dest):如果路径名相同,就是改名;如果路径名不同,就是改名并剪切。
public boolean isDirectory():判断是否是目录
public boolean isFile():判断是否是文件
public boolean exists():判断是否存在
public boolean canRead():判断是否可读
public boolean canWrite():判断是否可写
public boolean isHidden():判断是否隐藏

Ⅴ获取文件信息

public String getAbsolutePath():获取绝对路径
public String getPath():获取相对路径
public String getName():获取名称
public long length():获取长度、字节数
public long lastModified():获取最后一次的修改时间,毫秒值

在这里插入图片描述

Ⅵ目录遍历

public String[] list() :返回一个String数组,表示该File目录中的所有子文件或目录
public File[] listFiles() :返回一个File数组,表示该File目录中的所有的子文件或目录
public String[] list(FilenameFilter filter):使用文件过滤器作为参数,返回过滤出符合条件的所有子文件或目录
public File[] listFiles(FilenameFilter filter):使用文件过滤器作为参数,返回过滤出符合条件的所有子文件或目录

FilenameFilter接口的源码如下:

public interface FilenameFilter {
//测试指定文件是否应该包含在某一文件列表中。
//参数:File被找到的文件所在的目录,name文件的名称。
boolean accept(File dir, String name);
}

public class FileFor {
    public static void main(String[] args) {
        File dir = new File("D:/dir");
      	/获取当前目录下的文件以及文件夹的名称
		String[] names = dir.list();
		for(String name : names){
			System.out.println(name);
		}
        /获取当前目录下的文件以及文件夹对象,只要拿到了文件对象,那么就可以获取更多信息
        File[] files = dir.listFiles();
        for (File file : files) {
            System.out.println(file);/此输出为文件的路径名
        }
    }
}

listFiles在获取指定目录下的文件或者文件夹时必须满足下面两个条件
1,指定的目录必须存在
2,指定的必须是目录。否则容易引发返回数组为null,出现NullPointerException异常

public class FilenameFilterDemo {
    public static void main(String[] args) {
        File file = new File("D://");
        //将实现FilenameFilter接口的匿名类作为list()的参数
        String[] strArray = file.list(new FilenameFilter() {
        @Override
        public boolean accept(File dir, String name) {
                return new File(dir, name).isFile() && name.endsWith(".txt");
            }
        });
        for (String s : strArray) {
            System.out.println(s);
        }
    }
}

四、字节流

Ⅰ字节输出流OutputStream

java.io.OutputStream抽象类是表示字节输出流的所有类的超类(父类),将指定的字节信息写出到目的地。

字节输出流的基本共性功能方法:

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

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

Ⅱ字节输入流InputStream

java.io.InputStream抽象类是表示字节输入流的所有类的超类(父类),可以读取字节信息到程序中。
字节输入流的基本共性功能方法:

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

五、文件字节流

ⅠFileOutputStream

是OutputStream的子类,拥有OutputStream的方法;
1、构造方法:
public FileOutputStream(File file):根据File对象为参数创建对象。
public FileOutputStream(String name): 根据名称字符串为参数创建对象。(推荐用这种)
当创建该流对象时,必须直接或者间接传入一个文件路径,在该路径下,如果没有这个文件,会创建该文件。如果有这个文件,会清空这个文件的数据。
2、写数据到文件
public void write(int b):虽然参数为int类型四个字节,但是只会保留一个字节的信息写出。
public void write(byte[] b)
public void write(byte[] b,int off,int len)
这些都继承于OutputStream抽象类;

每次程序运行,每次创建输出流对象,都会清空目标文件中的数据。 可以在构造方法中再添加一个参数,即:
public FileOutputStream(File file, boolean append)
第二个参数默认为false,每次程序运行会覆盖文件
若设置为true,则每次运行程序会追加到文件末尾
写入一个换行: fos.write("\r\n".getBytes());
回车符:回到一行的开头(return)。
换行符:下一行(newline)。
系统中的换行:
Windows系统里,每行结尾是 回车+换行 ,即\r\n;
Unix系统里,每行结尾只有换行 ,即\n;
Mac系统里,每行结尾是回车,即\r。从 Mac OS X开始与Linux统一。

public static void File_output(String file) throws IOException//【文件输出流】【写】程序-》文件
{
    File file1 = new File(file);
    FileOutputStream out = new FileOutputStream(file1,true);//true追加,false覆盖,默认为false
    String line="abs";
    byte[] b =line.getBytes(); //将String类型转化成byte数组
    out.write(97);/写入一个字节数据
    out.write(line,0,1);/写入指定范围的数据
    fos.write("\r\n".getBytes());/ 写出一个换行, 换行符号转成数组写出
    out.write(b);/将字节数组b的内容写到输出流中
    out.close();
}
ⅡFileInputStream

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

2、其他方法

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

public static void File_input(String file) throws IOException//【文件输入流】【读取】文件-》程序
{
    File file1 = new File(file);
    FileInputStream in = new FileInputStream(file1);
    
    //①循环读取
    int n ;
    while ((n = in.read())!=-1) {//每次读取一个字节,存放到int变量中,当为-1时即为读取结束
      System.out.print((char)n);
    }
    
    //②字节数组为读取单位【推荐这种】
    byte[] b = new byte[100];
    while (( len= in.read(b))!=-1) {
      System.out.println(new String(b,0,len));// 每次读取后,把数组变成字符串打印
    }
    
    in.close();
}

六、字符流

字节流对于含有中文的数据流时会出现乱码,可能不会显示完整的字符,那是因为一个中文字符占用多个字节存储。
字符流就可以解决这个问题。字符流本质其实就是基于字节流读取时,去查了指定的码表。

字符流 = 字节流 + 编码表

如果处理纯文本的数据优先考虑字符流,其他情况就只能用字节流了(图片、视频、等等只文本例外)。

Ⅰ字符输入流Reader

java.io.Reader抽象类是字符输入流的所有类的超类(父类)
字符输入流的共性方法:

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

Ⅱ字符输出流Writer

java.io.Writer抽象类是字符输出流的所有类的超类(父类)
字符输出流的基本共性功能方法:

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():关闭此流,但要先刷新它。

七、文件字符流

文件字符流是Reader、Writer的子类;

ⅠFileReader

java.io.FileReader类是写出字符到文件的便利类。构造时使用系统默认的字符编码(UTF-8)和默认字节缓冲区。
1、构造方法:
FileReader(File file): 创建一个新的FileReader ,给定要读取的File对象。
FileReader(String fileName): 创建一个新的 FileReader ,给定要读取的文件的字符串名称。
2、其他方法:

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

public static void main(String[] args) throws IOException {
    FileReader fr = new FileReader("file1");

//①每次读取一个字符
    int b;
    while ((b=fr.read())!=-1){
      System.out.print((char) b);
    }
    
//②每次读取一个字符数组
    int length;
    char[] chars=new char[100];
    while ((length=fr.read(chars))!=-1){
        System.out.print(new String(chars,0,length));/new String(chars,0,length)可以防止读取到最后一行的空白字符
    }
    fr.close();
}
ⅡFileWriter

1、构造方法:
FileWriter(File file): 创建一个新的 FileWriter,给定要被写入数据的File对象。
FileWriter(String fileName): 创建一个新的 FileWriter,给定要被写入数据文件的名称。

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():关闭此流,但要先刷新它

一定要close()
【注意】关闭资源时,与FileOutputStream不同。 如果不关闭,数据只是保存到缓冲区,并未保存到文件。
【注意】关闭资源时,与FileOutputStream不同。 如果不关闭,数据只是保存到缓冲区,并未保存到文件。
【注意】关闭资源时,与FileOutputStream不同。 如果不关闭,数据只是保存到缓冲区,并未保存到文件。

flush()与close()方法作用都可以刷新缓冲
flush :刷新缓冲区,流对象可以继续使用。
close:先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。

class FWWrite {
    public static void main(String[] args) throws IOException {
        // 使用文件名称创建流对象
        FileWriter fw = new FileWriter("fw.txt",true);

        //① write(char[] c)
        String line="字符输出流";
        char[] chars=line.toCharArray();
        fw.write(chars);
        fw.flush();//刷新缓冲区

        //② write(String s)
        fw.write("\r\n");
        fw.write("换行");
        fw.flush();

        //③ write(int c)
        fw.write('刷');
        fw.write('新');
        fw.write('关');
        fw.write('闭');
        fw.close();
    }
}

字符流与字节流在方法的使用方面是大致相似的


八、缓冲流

缓冲流,也叫高效流,是对4个FileXxx 流的“增强流”。

缓冲书写格式为BufferedXxx,按照数据类型分类:

  • 字节缓冲流:BufferedInputStreamBufferedOutputStream
  • 字符缓冲流:BufferedReaderBufferedWriter
Ⅰ字节缓冲流

构造方法:
public BufferedInputStream(InputStream in):创建一个新的缓冲输入流,参数类型InputStream
public BufferedOutputStream(OutputStream out):创建一个新的缓冲输出流,参数类型OutputStream
可看作是对字节流的包装

//构造方式一: 创建字节缓冲输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("b.txt"));

//构造方式二: 创建字节缓冲输出流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.txt"));
Ⅱ字符缓冲流

构造方法:
public BufferedReader(Reader in) :创建一个新的缓冲输入流,参数类型为Reader。
public BufferedWriter(Writer out): 创建一个新的缓冲输出流,参数类型为Writer。
可看作是对字符流的包装

// 创建字符缓冲输入流
BufferedReader br = new BufferedReader(new FileReader("b.txt"));
// 创建字符缓冲输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
字符缓冲流特有方法

BufferedReader:public String readLine(): 每次读取一行数据读取到最后返回null
BufferedWriter:public void newLine(): 写入一个换行,由系统属性定义符号。
【只是字符缓冲流有这些特有方法】
【缓冲流也可以使用被包装的流对象中的方法】

class BufferedReaderDemo {
    public static void main(String[] args) throws IOException {
        // 创建流对象
        BufferedReader br = new BufferedReader(new FileReader("fw.txt"));
//①每次读取一个字符数组
        char[] chars=new char[100];
        int len=-1;
        while((len=br.read(chars))!=-1){
            System.out.println(new String(chars,0,len));
        }
//②每次读取一行
        String line = null;
        // 循环读取,读取到最后返回null
        while ((line = br.readLine()) != null){
            System.out.println(line);
        }
        
        // 释放资源
        br.close();
    }
}

九、转换流

InputStreamReader类:字节-----》字符(读取为字节,解码为字符)
OutputStreamWriter类:字符-----》字节(写出为字符,编码为字节)

Ⅰ字符编码与解码

众所周知,计算机中储存的信息都是用二进制数表示的,而我们在屏幕上看到的数字、英文、标点符号、汉字等字符是二进制数转换之后的结果。按照某种规则,将字符存储到计算机中,称为编码 。反之,将存储在计算机中的二进制数按照某种规则解析显示出来,称为解码 。比如说,按照A规则存储,同样按照A规则解析,那么就能显示正确的文本符号。反之,按照A规则存储,再按照B规则解析,就会导致乱码现象。

String(byte[] bytes, String charsetName):通过指定的字符集解码字节数组
byte[] getBytes(String charsetName):使用指定的字符集合把字符串编码为字节数组

编码:
String -- byte[]

解码:
byte[] -- String

(1)字符编码 Character Encoding: 就是一套自然语言的字符与二进制数之间的对应规则
(2)字符集 Charset:也叫编码表。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等。常见字符集有ASCII字符集、GBK字符集、Unicode字符集等。

一套字符集可对应不止一套字符编码
在这里插入图片描述
ASCII:是基于拉丁字母的一套电脑编码系统,用于显示现代英语,主要包括控制字符(回车键、退格、换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号)。
①基本的ASCII字符集,使用7位(bits)表示一个字符,共128字符。
②ASCII的扩展字符集,使用8位(bits)表示一个字符,共256字符,方便支持欧洲常用字符。

GB2312:简体中文码表。一个小于127的字符的意义与原来相同。但两个大于127的字符连在一起时,就表示一个汉字,这样大约可以组合了包含7000多个简体汉字,此外数学符号、罗马希腊的字母、日文的假名们都编进去了,连在ASCII里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的"全角"字符,而原来在127号以下的那些就叫"半角"字符了。
GBK最常用的中文码表。是在GB2312标准基础上的扩展规范,汉字占2个字节、英文字母占1个字节,共收录了21003个汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等。

Unicode字符集 :
Unicode编码系统为表达任意语言的任意字符而设计,是业界的一种标准,也称为统一码、标准万国码
它最多使用4个字节的数字来表达每个字母、符号,或者文字。有三种编码方案,UTF-8、UTF-16和UTF-32。最为常用的UTF-8编码。
UTF-8编码,可以用来表示Unicode标准中任何字符,它是电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。所以,我们开发Web应用,也要使用UTF-8编码。它使用一至四个字节为每个字符编码。
编码规则:

①128个US-ASCII字符,只需一字节编码。
②拉丁文等字符**,需要二字节编码。
③大部分常用字(含中文),使用三字节编码。
④其他极少使用的Unicode辅助字符,使用四字节编码。

(3)编码问题导致乱码
出现乱码的原因就是文本字符编码过程与字节流解码过程使用了不同的编码格式
在java开发工具IDEA中,使用FileReader 读取项目中的文本文件。由于IDEA的设置,都是默认的UTF-8编码,对于读取非UTF-8编码的文本文件时,就会出现乱码。

ⅠInputStreamReader类

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

构造方法
InputStreamReader(InputStream in): 创建一个使用默认字符集的字符流。(UTF-8)
InputStreamReader(InputStream in, String charsetName): 创建一个指定字符集的字符流。

参数为字节流对象。

转换:将字节文件按指定编码解码读取为字符数据;

class ReaderDemo2 {
    public static void main(String[] args) throws IOException {
        // 定义文件路径,文件为UTF-8编码
        String FileName = "D:/four.txt";
        // 创建流对象,默认UTF-8编码
        InputStreamReader isr = new InputStreamReader(new FileInputStream(FileName));
        // 创建流对象,指定GBK编码
        InputStreamReader isr2 = new InputStreamReader(new FileInputStream(FileName) , "GBK");
        // 定义变量,保存字符
        int read;
        // 使用UTF-8编码字符流读取UTF-8编码文件
        while ((read = isr.read()) != -1) {
            System.out.print((char)read); //正常读取
        }
        isr.close();
        // 使用GBK编码字符流读取UTF-8编码文件
        while ((read = isr2.read()) != -1) {
            System.out.print((char)read);//出现乱码
        }
        isr2.close();
    }
}
ⅡOutputStreamWriter类

OutputStreamWriter为从字符流到字节流的桥梁。使用指定的字符集将字符编码为字节。它的字符集可以由名称指定,也可以接受平台的默认字符集。

构造方法
OutputStreamWriter(OutputStream in): 创建一个使用默认字符集的字符流。
OutputStreamWriter(OutputStream in, String charsetName): 创建一个指定字符集的字符流。

参数为字节输出流对象

转换:将字符流数据以指定编码写入字节文件;

class OutputDemo {
    public static void main(String[] args) throws IOException {
        // 定义文件路径
        String FileName = "D:\\file1.txt";
        // 创建流对象,默认UTF8编码
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(FileName));
        // 写出数据
        osw.write("默认编码"); 
        osw.close();

        // 定义文件路径
        String FileName2 = "D:\\file2.txt";
        // 创建流对象,指定GBK编码
        OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream(FileName2),"GBK");
        // 写出数据
        osw2.write("GBK编码");
        osw2.close();
    }
}

十、序列化流

何谓序列化?
Java提供了一种对象序列化的机制。用一个字节序列可以表示一个对象,该字节序列包含该对象的数据、对象的类型和对象中存储的属性等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息

反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化。对象的数据、对象的类型和对象中存储的数据信息,都可以用来在内存中创建对象。

ⅠObjectOutputStream类

java.io.ObjectOutputStream 类,将Java对象的原始数据类型写出到文件,实现对象的持久存储。

一个对象要想序列化,必须满足两个条件:
(1)、该类必须实现java.io.Serializable 接口。

①Serializable是一个标记接口,不实现此接口的类将不会使任何状态序列化或反序列化,会抛出NotSerializableException 。
②该类的所有属性必须是可序列化的
③如果有一个属性不需要可序列化的,则该属性必须注明是瞬态的,使用transient 关键字修饰。

class Employee implements java.io.Serializable {
    public String name;//普通成员变量,可以被序列化
    public String address;
    public transient int age; // transient瞬态修饰成员,不会被序列化
    public Employee(String name, String address, int age) {
        this.name = name;
        this.address = address;
        this.age = age;
    }
}

(2)、写出对象方法
public final void writeObject (Object obj) : 将指定的对象写出,实现对象序列化。

class SerializeDemo {
    public static void main(String[] args) throws IOException {
        Employee e = new Employee("tom", "USA", 1);
        // 创建序列化流对象
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("employee.txt"));
        // 将对象写出,序列化
        out.writeObject(e);
        // 释放资源
        out.close();

    }
}
ⅡObjectInputStream类

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

反序列化需要用到的方法:
(1)、构造方法:
public ObjectInputStream(InputStream in): 创建一个指定InputStream的ObjectInputStream。
(2)、public final Object readObject () : 读取一个对象。

class DeserializeDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {

        // 创建反序列化流
        FileInputStream fileIn = new FileInputStream("employee.txt");
        ObjectInputStream in = new ObjectInputStream(fileIn);
        // 读取一个对象
        Employee e = (Employee) in.readObject();
        // 释放资源
        in.close();
        fileIn.close();

        // 无异常,直接打印输出
        System.out.println("Name: " + e.name);    // tom
        System.out.println("Address: " + e.address); // usa
        System.out.println("age: " + e.age); / 0  没有被序列化 输出为默认值0
    }
}

十一、打印流

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

打印流特点:

1、只操作目的地,不操作数据源
2、可以操作任意类型的数据
3、如果启用了自动刷新,在调用println()方法的时候,能够换行并刷新
4、可以直接操作文件

打印流分类:
1、字节打印流PrintStream

public class PrintStreamDemo {
    public static void main(String[] args) throws IOException {
        BufferedReader br=new BufferedReader(new FileReader("copy.txt"));
        PrintStream ps=new PrintStream("printcopy.txt");
        String line;
        while((line=br.readLine())!=null) {
            ps.println(line);
        }
        br.close();
        ps.close();
    }
}

2、字符打印流PrintWriter

/**
 * 使用打印流复制文本文件:将aa中的内容读取,再写到pw表示的文件中;
 */
class PrintWriterDemo {
    public static void main(String[] args) throws IOException {
        BufferedReader br=new BufferedReader(new FileReader("aa.txt"));
        PrintWriter pw=new PrintWriter("printcopyaa.txt");
        String line;
        while((line=br.readLine())!=null) {
            pw.println(line);
        }
        br.close();
        pw.close();
    }
}

主要就是使用print()与println()方法

十二、Properties

概述
java.util.Properties 继承于Hashtable ,来表示一个持久的属性集。它使用键值结构存储数据,每个键及其对应值都是一个字符串。该类也被许多Java类使用,比如获取系统属性时,System.getProperties 方法就是返回一个Properties对象。

构造方法
public Properties() :创建一个空的属性列表。

基本的存储方法

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

public class ProDemo {
    public static void main(String[] args) throws FileNotFoundException {
        // 创建属性集对象
        Properties properties = new Properties();
        // 添加键值对元素
        properties.setProperty("filename", "a.txt");
        properties.setProperty("length", "209385038");
        properties.setProperty("location", "D:\\a.txt");
        // 打印属性集对象
        System.out.println(properties);
        // 通过键,获取属性值
        System.out.println(properties.getProperty("filename"));
        System.out.println(properties.getProperty("length"));
        System.out.println(properties.getProperty("location"));

        // 遍历属性集,获取所有键的集合
        Set<String> strings = properties.stringPropertyNames();
        // 打印键值对
        for (String key : strings ) {
          	System.out.println(key+" -- "+properties.getProperty(key));
        }
    }
}

与流相关的方法
public void load(InputStream inStream): 从字节输入流中读取键值对。

参数中使用了字节输入流,通过流对象,可以关联到某文件上,这样就能够加载文本中的数据了。现在文本数据格式如下:

filename=Properties.txt
length=123
location=C:\Properties.txt
public class ProDemo {
    public static void main(String[] args) throws FileNotFoundException {
        // 创建属性集对象
        Properties pro = new Properties();
        // 加载文本中信息到属性集
        pro.load(new FileInputStream("Properties.txt"));
        // 遍历集合并打印
        Set<String> strings = pro.stringPropertyNames();
        for (String key : strings ) {
          	System.out.println(key+" -- "+pro.getProperty(key));
        }
     }
}

文本中的数据,必须是键值对形式,可以使用空格、等号、冒号等符号分隔。

十三、IO异常

使用IO流时,可能会产生文件找不到等IO异常,因此我们要将异常进行处理,通常是使用try...catch...finally 代码块;
格式如下:

public class HandleException1 {
    public static void main(String[] args) {
      	// 声明流变量
        FileWriter fw = null;
        try {
            //创建流对象
            fw = new FileWriter("fw.txt");
            // 写数据
            fw.write("数据"); 
            
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
            //关闭
                if (fw != null) {
                    fw.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

即创建流对象、写数据的过程中会存在异常,需要对这块进行try处理,关闭流则要放在finally语句块中;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值