在Java里,读文件、输入输出是属于非常常用的部分,里面有很多类,之前一直就没搞清楚过。。。。。
终于有机会可以把输入输出这部分的内容捋捋了~
Tip:
这部分有很多相通的地方,从官方参考文档可以看的更具体,这里放一下参考文档的链接,可以时常参考
Java官方文档:https://docs.oracle.com/javase/8/docs/api/index.html
注:
常用的16个流,可以分为InputStream、OutputStream、Reader、Writer四个类(同时也是父类)
FileInputStream | FileOutputStream |
---|---|
FileReader | FileWriter |
BufferedInputSream | BufferedOutputSream |
BufferedReader | BufferedWriter |
DataInputStream | DataOutputStream |
ObjectInputStream | ObjectOutputSream |
OutputSreamReader | InputStreamReader |
PrintWriter | PrintStream |
还是用类结构图表明一下IO流之间的关系
属于java.io包,文件字节流
应用的话,我们直接上例子比较容易理解一点
import java.io;
public class Test1{
public static void main(String[] args){
/*注意点:
IO流函数调用可能会报错,所以在调用前需要处理错误
代码里省略了处理错误的部分
如果自学的话,可以try-catch简单处理一下
如果是实际应用,报错信息可以参考官方文档,内容更详细
*/
String filePath="C:\\test.txt";
//创建一个文件输入流
FileInputStream fis=new FileInputStream(filePath);
//构造函数也可以传递File类型的参数
//开始读文件
int temp=0;
//read()是开始读文件,每次返回的是一个字节
//int接受是因为ASCII码值,英文由一个字节可以读完
//当返回值为-1时是文件读完了
while((temp=fis.read())!=-1){
System.out.print(temp);
}
//其他读文件的方式
//提前准备字节数组,读取的效率会高些,1024表示读1kB大小的文件
byte[] temp=new int[1024];
while(fis.read(temp)!=-1){
System.out.print(temp.toString());
}
//其他会用到的函数
//判断流中剩余的预估字节数
fis.available();
//跳过多少字节不读取
fis.skip(1024);//直接跳过了1kB字节不读
//通常流完成任务要关闭,避免资源浪费
fis.close();
}
}
和FileInputStream可以类比着记忆,很多是一样的,只是一个是输入,一个是输出
具体的应用还是直接上例子
import java.io;
public class Test2{
public static void main(String[] args){
/*
IO流函数调用可能会报错,解释如上
*/
String filePath="C:\\TestOutput.txt";
//创建一个文件输出流
FileOutputStream fos=new FileOutputStream(filePath);
//构造函数也可以传递File类型的参数
//这里需要注意的是:
//1.如果输出的文件不存在的话,会创建文件
//2.构造函数里还有一个boolean类型的参数,判断是否以追加的方式写入
//开始写文件
int x=89;
fos.write(x)
//其他写文件的方式
//可以用字节数组写文件
//byte[] filecontent={};
//用数组写文件的时候,可以选择全部写,也可以设定写中间一段
//函数是:fos.write(filecontent,起始int值,结束int值)
//fos.write(filecontent);
//强制刷新
//一般建议加上,保证文件全部写入
fos.flush();
//通常流完成任务要关闭,避免资源浪费
fos.close();
}
}
属于java.io包,文件字节流
父类InputStreamReader,是一种转换流,将字节流转换为字符流
和InputStreamReader有很多相似的地方
官方文档可以看见,FileReader的方法基本都是继承自父类的
这里只说一个区别点,和FileInputStream不同,FileReader的read函数,可以接受char类型数组
这个区别的优势:文件流可以直接读一个中文字符了,一定程度能避免出现乱码
和FileReader是类似的
方法里特殊的点也在于write函数,传递的参数可以是char[]和String了
Tip:BufferedReader的介绍中有涉及InputStreamReader的使用内容
为了后面理解比较方便,一些内容先提前一点说明吧~
1. 关于System.in
从文档里可以看到,System.in是一个属性,是标准的输入流,是InputStream类,所以用System.in接收控制台输入的时候,得到的是InputStream
2. 关于InputStreamReader
前面有简单说明,InputStreamReader是字符流和字节流之间的一个转换类,将字节流转化为字符流
InputStreamReader的构造方法需要InputStream类型参数(暗示前面提到的System.in),同时,在构造参数中,可以指定字符编码,缺省表示默认编码
InputStreamReader本身也有read()方法,可以读取文件,但通常情况下,采用效率更高的方式
什么方式呢???
将InputStreamReader包装在BufferedReader中:
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
重点一:读取
除了Reader和InputStream都会用到的read(),BufferedReader的特别之处在于有一个效率更高的函数
String readLine()
这个函数的厉害之处就在于,每次直接读一行的内容,这个效率就很高了
当然,这个函数的缺点在于,每次读一行,读出来之后没有换行符。。。。。。
这时候再判断文件是否读完,直接判断函数的返回值是否为null
重点二:关闭流
虽然我们用了InputStreaReader创建BufferedReader,但最后用完关闭流的时候,直接关闭BufferedReader对象就可以了
(1)作用
可以对类进行扩展,降低程序的耦合度
(2)思路
(3)举个栗子
注意点:
public abstract class Reader{
public abstract void close();
}
public class FileReader extends Reader{
public void close(){
System.out.println("FileReader closed!");
}
}
public class BufferedReader extends Reader{
Reader reader;
public BufferedReader(Reader reader){
//采用的是多态的方式,FileReader对象也可以传进来
this.reader=reader;
}
public void close(){
System.out.println("FileReader类的扩展内容");
reader.close();
}
}
和BufferedReader也是类似的
划重点:
Writer out
= new BufferedWriter(new FileWriter(filepath));
或者
Writer out
= new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filepath,boolean)));
写文件的时候也有一个新函数newLine(),会直接写一个换行符
同样建议在写完后,用flush刷新一下,保证所有内容输出
(1)归属
java.io下
(2)优势
针对数据的IO流,可以直接根据数据类型读、写数据,不需要再进行数据类型转换
(1)实例化对象
new DataOutputStream(OutputStream)
(2)DataOutputStream输出
可以直接用write(byte[]/int)输出
也可以选择对应的数据类型进行数据,类里有的函数如下表
注意点:输出的信息是有固定格式的,所以直接打开写的文件可能会乱码
返回值 | 函数 |
---|---|
void | writeBoolean(boolean v) |
void | writeByte(int v) |
void | writeBytes(String s) |
void | writeChar(int v) |
void | writeChars(String s) |
void | writeDouble(double v) |
void | writeFloat(float v) |
void | writeInt(int v) |
void | writeLong(long v) |
void | writeShort(int v) |
void | writeUTF(String str) |
和DataOutputStream是对应的,也是类似的,就类比着来吧
这趴过~
标准输出流,字节流形式,通常用来打印信息到控制台
PrintStream=System.out
可以改变输出流的输出位置,使之输出到固定文件夹下
需要应用到System包中的static void setOut(PrintStream out)函数
举个栗子
System.setOut(new PrintStream(new FileOutputStream("log.txt")));
//此时输出信息就会写在log.txt文件中
System.out.println("test");
也是标准输出流,字符流形式
用的相对PrintStream会少些
后面会用到,先介绍一下吧
(1)含义
将Java对象的状态保存到硬盘中
(2)要求
Java对象实现序列化接口Serializable
(3)Serializable接口
java.io包下,没有具体的方法,属于一种标志化的接口
(4)Serializable本质
给Java类添加了一个序列化版本号的属性
建议手动提供序列化版本号(因为当序列化版本号不一致时,序列化会出错)
举个栗子
static final long seralVersionUID=123456L;
(5)其他
需要排除Java类中某个属性不需要参加序列化的时候,用transient关键词修饰
通常会用ObjectOutputStream来序列化Java对象到硬盘中(序列化写)
具体写的流程,写个栗子吧
//创建Java对象
Student stu=new Student("Li Ming",20);
//创建输出流
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("data"));
//写对象
oos.writeObject(stu);
//刷新、关闭
oos.flush();
oos.close();
与序列化相对应,反序列化
和ObjectOutputStream相似,类比着用吧~~
前面好像说了很多File对象,也是比较常用的一个类,这里补一下
File类在java.io下,不是流,不能进行读写操作
File类是计算机中文件夹和文件的抽象表现,一般用来操作文件的
形参一般是String或者URL,文件的相对路径或者绝对路径都可以
当且仅当具有此名称的文件还不存在时,创建新的空文件
判断文件是否存在
获取文件的绝对路径
获取文件名
获取文件父文件路径
判断是否为文件
判断是否为目录
返回文件最后一次修改的时间
返回文件绝对路径的长度
在文件不存在的时候,创建路径名指定的文件目录
和mkdir类似,不同的是创建路径名指定的多重文件目录
以上。
IO流的内容就是这样了,基本总结的都是比较常用的,不常用的就慢慢积累吧,其中很多相通的内容