java io流

起因:学习网编,发现里面的课程大量用到了io的知识,十分影响学习,所以转战io

何为“流”

流:数据在数据源(文件)和程序(内存)之间经历的路径

输入流:数据从数据源(文件)到程序(内存)的路径

输出流:数据从程序(内存)到数据源(文件)的路径

代码最后要关闭流,释放资源。关闭时写在条件if流!= null(说明流用过了)

创建文件

File file=new File(String pathname);//根据路径构建一个File对象 例子:“e:\\news1.txt”
File file=new File(File parent,String child);//根据父目录文件+子路径创建 例子:"e:\\","news2.txt"
File file=new File(String parent,String child)//根据父目录+子路径创建 例子:"e:\\","news3.txt"
//上面三种方法只是在内存中创建file对象,还没有输出到硬盘里面
file.creatNewFile();//真正创建对象

file对象信息

file.getName()//获得文件名
file.getAbsolutePath()//获得绝对路径
file.getParent()//获得父级目录
file.length()//获得文件大小(字节)
file.exists()//判断文件是否存在
file.isFile()//判断是不是一个文件
file.isDirectory//判断是不是一个目录
file.delete//删除文件,返回值是布尔值,成功为1

目录操作

mkdir创建一级目录,mkdirs创建多级目录,delete删除目录或文件。这三个方法都会返回一个布尔值

在java中目录也被当成文件,所以使用时file方法。比如一个目录既可以使用filePath也可以使用directoryPat

流的分类

  • 按操作数据单位不同分为:字节流(8bit)【操作二进制文件保证无损】,字符流(按字符)【文本文件效率更高】
  • 按数据流的流向不同分为:输入流,输出流
  • 按流的角色的不同分为:节点流,处理流/包装流
抽象基类 字节流 字符流
输入流 InputStream Reader
输出流 OutputStream Writer

上面的四个都是抽象类

FileInputStream

InputStream是字节输入流

InputStream抽象类是所有类字节输入流的超类

InputStream常用的子类

  1. FileInputStream文件输入流
  2. BufferedInputStream缓冲字节输入流
  3. ObjectInputStream对象字节输入流

read

  • read( )返回值如果为-1,表示读取完毕,所以一般仍在while的括号中。read返回值是int,在输出时需要强转为char才能输出字符

  • read(byte[ ] b)可以提高效率,不一个一个读取字节。

    • 如果返回-1,表示读取完毕
    • 如果读取正常,返回实际读取的字节数
    • 最多读b.length个字节

​ java中创建数组的方法

byte[] buf = new byte[8];

while((readLen = fileInputStream.read(buf))!=-1){
    sout(new String(buf,0,readLen));
}
//如果文件里内容是Hello,world(大于8个字节)
/*行为逻辑:先读取8个字节,readLen值为8,运用new String(buf,0,readLen)将buf数组中0到readLen(左闭右开)的元素转化为一个字符串
第二次,读取剩下三个,readLen为3,同上
第三次,无法读取,readLen为-1,循环结束

字节流无法读取汉字,因为一个汉字不止一个字节,会出现乱码,所以要用字符流

FileOutputStream

write与read用法类似

write(byte[ ] b)中需要用到一个string类型自带的方法 .getBytes 使字符串转换位一个字节数组

注意:如果使用new FileOutputStream(filepath)的方式,当写入内容时会覆盖原来的内容。使用new FileOutputStream(filepath,true)则写入的内容使从末尾追加的

一定要使用write(byte[ ] b, 0 ,readLen)第一个是byte数组,第二个是写出的起始位置,第三个readLen是自定义的,值为每次fileInputStream.read( byte[] b )的返回值。 防止最后一次数组没填充完,将不属于本次写入的数据也写出

文件字符流

FileReader和FileWriter是字符流,即按照字符来操作IO

FileReader相关用法

  1. new FileReader(File/String) 创建对象
  2. read方法:每次读取单个字符,返回该字符,如果到文件末尾返回-1
  3. read(char [ ] ):批量读取多个字符到数组,返回读取到的字符数,如果到文件末尾返回-1
  • new String(char[ ])将char[ ]转换成String
  • new String(char[ ],off,len):将char[ ]的指定部分转换成String

FileWriter相关用法

  1. new FileWriter(File/String) 创建对象,覆盖模式,相当于流的指针在首端
  2. new FileWriter(File/String , true) 创建对象,覆盖模式,相当于流的指针在尾端
  3. write(int):写入单个字符
  4. write方法:每次写入单个字符,返回该字符,如果到文件末尾返回-1
  5. write(char [ ] ):批量写入多个字符到数组,返回写入到的字符数,如果到文件末尾返回-1。可以用(char[ ],off,len)指定部分
  6. write(string):写入整个字符串 可以用(string,off,len)指定部分
  • toCharArray将String转换成char[ ]

FileWriter使用后,必须要关闭close或者刷新flush,否则写入不到指定文件

节点流处理流

节点流:对特定的数据源读写数据,如FileReader,FileWrite

处理流(包装流)是连接在已存在的流(节点流或处理流),为程序提供更为强大的读写功能,如BufferedReader,BufferedWriter

BufferedReader类中,有属性Reader,即可以封装一个节点流,该节点流可以是任意的,只要是Reader的子类

writer同理

处理流设计模式

处理流(包装流)包装节点流,既可以消除不同节点流的实现差异(有些对文件操作,有些对管道操作,有些对数组操作),也可以提供更方便的方法来完成输入输出

关闭处理流时,会自动关闭他调用的节点流

Buffered使用方法

实例化Buffered,并且使用他的含参构造器,将需要使用的节点流输入进去。就可以通过对象buffered来实现某个节点流的方法

关闭时关闭buffered对象即可

对象处理流

对象流+处理流:OjectInputStream(完成反序列化) ObjectOutputStream(完成序列化)

需求

  1. 将int num=100这个int数据保存在文件中,保证这个100是int类型而不是double,string等。能够从文件中直接恢复int 100;
  2. 将Dog dog = new Dog("小黄",3 )这个dog对象保存到文件中,并且能够从文件中恢复

上面的要求,就是能够将基本数据类型或者对象进行序列化和反序列化操作

为了让某个类是可序列化的,该类必须实现如下两个接口之一

  • Serializable//这是一个标记接口 推荐选这个
  • Externalizable 该接口有方法需要实现,比较麻烦

序列化后,保存的文件格式不是存文本的,而是按照他的格式来保存的

数据和类型

把他们写到ObjectOutputStream的对象的write方法里

int会包装为Integer,他实现了Serializable

boolean会包装为Boolean,他实现了Serializable

char会包装为Charater,他实现了Serializable

double会包装为Double,他实现了Serializable

String本身就实现了Serializable

对象

如果要序列化某个类的对象,就让他implements Serializable

序列化细节

保存类型通过 .writexxx实现,比如保存Int类型就是 .writeInt( ),不写明类型的话就只是保存数据

特别的 String用的是 .writeUTF 对象用的是 .writeObject( )

反序列化细节

反序列化的顺序需要和保存数码(序列化)的顺序一样

反序列话对象要把ois(OjectInputStream对象名).readObject( )赋值给Object 对象名(比如dog)。然后通过 dog . getClass( )查看他的运行类型,dog查看他的属性信息

查看对象属性信息细节

正常会输出奇怪数字

需要在序列化时在Dog类中重写Serializable的toString方法,此时可以反序列化正常输出dog的属性

调用dog的方法:如果序列化的Dog类不在反序列化类所在的包中,或者是私有的不可调用,则需要把Dog定义(整个代码)拷贝到反序列化类所在的保重或者直接拷贝到反序列化类的下方(可以调用private ) (总之要拷贝到可以引用的地方)(引用的方法是import)

原因:Object dog = ois.readObject( ) 中dog的编译类型是Object,无法调用Dog类的方法

对象处理流的使用细节整理

  1. 读写顺序要一致
  2. 要求实现序列化或反序列化对象,需要实现Serializable
  3. 实例化的类中建议添加SerialVersionUID,为了提高版本的兼容性
private static final long serialVersionUID = 1L;
//新增属性时,系统不会认识是创建了一个新类,而是更新了版本
  1. 序列化对象时,默认将里面所有属性都进行实例化,但除了static或transient修饰的成员
  2. 序列化对象时,要求里面属性的类型也需要实现序列化接口
  3. 序列化具备可继承性,父类已经实现了序列化,他的所有子类就都实现了序列化

标准输入输出流

类型 默认设备
System.in 标准输入 InputStream 键盘
System.out 标准输出 PrintStream 显示器

System.in 编译类型是InputStream 运行类型是BufferedInputStream

System.iout 编译类型是PrintStream 运行类型也是PrintStream

转换流

InputStreamReader:Reader的子类,可以将InputStream(字节流)包装(转换)成Reader(字符流)

OutputStreamWriter:Writer的子类,可以将OutputStream(字节流)包装成Writer(字符流

默认情况下读取文件用的是utf-8编码,但是如果读的是其他编码就会出现乱码(因为没有指定读取文件的编码方式)

字节流可以指定读取的编码方式

转换流可以把字节流转换为字符流。所以先通过字节流指定编码方式读取,然后再转换为字符流

InputStreamReader

InputStreamReader(InputStream,Charset)
//先指定一个InputStream子类,然后再指定编码类型

解决乱码问题

InputStreamReader isr = new InputStreamReader(new FileInputStream(filePath) , "gbk");
//先选用FileInputStream且采用gbk编码的字节流读取的方法,然后通过转换流包装为isr字符流
BufferedReader br = new BufferedReader(isr);
//将isr节点流转换为br处理流
String s = br.readLine( );

OutputStreamReader

与In相同,可以通过这种方法改变输出文件的编码方式

打印流

打印流只有输出流,没有输入流

PrintStream字节流

PrintWriter字符流

PrintStream

可以直接PrintStream out = System.out;创建一个out对象

在默认情况下,输出数据的位置是标准输出,即显示器

PrintStream编译类型的对象out有一个print方法,其底层是运用的write方法,所以也可以直接调用out的write方法

可以通过

System.setOut(new PrintStream("e:\\f1.txt"));

来修改打印流输出的位置/设备

Properties类

配置文件的格式

键=值

键=值

注意:键值对不需要有空格,值不需要用引号。默认为String类型

常用方法

load:加载配置文件的键值对到Properties对象

list:将数据显示到指定设备/流对象

getProperty(key):根据键获取值

setProperty(key,value):设置键值对到Properties对象,如果key存在就是修改,不存在就是新建

store:将Properties中的键值对存储到配置文件,在idea中,保存信息到配置文件,如果含有中文,会储存为unicode值 store( )括号中第一个是输出流和新文件(修改文件)地址,第二个如果输入一个字符串就可以作为这个新文件的一个注释

posted @ 2023-01-20 17:39  Zaughter  阅读(19)  评论(0编辑  收藏  举报