I/O操作
Java的IO 类和接口存在于java.IO包中
总结:重点掌控:
1): 文件流 :字节/字符,读取/写入流. File开头的四个类
2): 缓冲流: 字节/字符,缓冲读取/写入流.Buffered开头的四个类
3): 对象流-序列化和反序列化(重点了解): ObjectOutputStream / ObjectInputStream
4): 打印流: printStream / printWriter
5): 转换流(字节转换成字符)InputStreamReader/OutputStreamWriter
Java1.7开始使用Files.copy(Path source, OutputStream out);将文件中的所有字节复制到目标文件
File类(文件)
介绍和路径分隔符:
File类是IO包中唯一表示磁盘文件和磁盘目录的对象的路径
该类包含了创建、删除文件、重命名文件、判断文件读写权限以及文件是否存在,查询等功能方法。
只能设置和获取文件本身的信息,不能设置和获取文件的内容。
路径分隔符、属性分隔符
Unix: 使用“/”来分割目录路径。 使用“:”来分割属性
windows:使用“\”来分割目录路径。也支持“/”。 使用“;”来分割属性
---------------------------------------------
File提供了两类常亮分别来提供路径分割符、属性分隔符。
1):路径分隔符
2):属性分隔符
表示文件路径:
操作File的路径和名称
File getAbsoluteFile() 返回绝对路径名。
String getAbsolutePath() 返回绝对路径名。
String getPath() 返回文件路径。
String getName() 返回由文件的名称。
String getParent() 返回上级目录文件。
File getParentFile() 返回此上级目录路径。
public static void test1(){
// 创建对象
File file = new File("F:/Eclipse/eclipse/tset.java");
System.out.println(file.getAbsoluteFile());//F:\Eclipse\eclipse\tset.java
System.out.println(file.getAbsolutePath());//F:\Eclipse\eclipse\tset.java
System.out.println(file.getName());//tset.java
System.out.println(file.getPath());//F:\Eclipse\eclipse\tset.java
System.out.println(file.getParent());//F:\Eclipse\eclipse
System.out.println(file.getParentFile());////F:\Eclipse\eclipse
}
检测File状态的方法
boolean canExecute() 测试应用程序是否可以执行的文件。
boolean canRead() 测试应用程序是否可以读取的文件。
boolean canWrite() 测试应用程序是否可以修改的文件。
boolean isHidden() 测试文件是否是一个隐藏文件。
long lastModified() 返回此文件最后一次被修改的时间(单位:毫秒)。
long length() 返回文件的长度大小(单位:字节)。
private static void test2() {
File file = new File("F:/Eclipse/eclipse/eclipse.exe");
System.out.println(file.canExecute());//true
System.out.println(file.canRead());//true
System.out.println(file.canWrite());//true
System.out.println(file.isHidden());//false
System.out.println(file.lastModified());//1475816570000
System.out.println(new Date(file.lastModified()).toLocaleString());
System.out.println(file.length());//319984
}
File类中方法:文件操作
boolean isFile() 是否是文件。
boolean createNewFile() 创建一个新的空文件。
static File createTempFile(String prefix, String suffix,File directory) 创建临时文件.
boolean delete() 删除文件 .
void deleteOnExit() 在JVM终止时,删除文件。
boolean exists() 判断文件是否存在。
boolean renameTo(File dest) 重新命名文件。
private static void test3() {
File file = new File("D:/搜狗高速下载/123456.txt");
System.out.println(file.isFile());//true
try {
new File("D:/搜狗高速下载/123456.java").createNewFile();//创建一个新的文件
} catch (IOException e) {
e.printStackTrace();
}
//file.renameTo(new File("D:/搜狗高速下载/456.txt"));
file.delete();
//创建临时文件static File createTempFile(String prefix, String suffix,File directory)
//(perfix临时文件前缀)( suffix临时文件后缀)(directory临时文件保存位置)
try {
File.createTempFile("apple", ".rar", new File("D:/搜狗高速下载"));
} catch (IOException e) {
e.printStackTrace();
}
}
File类中方法:目录操作
boolean isDirectory(); 判断是否是目录。
boolean mkdir(); 创建目录。
boolean mkdirs() 创建当前目录和上级目录.
String [] list(); 列出所有的文件名
File [] listFiles(); 列出所有文件对象
Static File[] listRoots();列出系统盘符.
boolean delete() 删除目录/文件 .
oid deleteOnExit() 在JVM终止时,删除目录/文件。
boolean exists() 判断文件/目录是否存在。
boolean renameTo(File dest) 重新命名目录/文件名。
public static void test4(){
File file = new File("D:");
File file1 = new File("D:/搜狗高速下载");
System.out.println(file.isDirectory());//false
System.out.println(file1.isDirectory());//true
file1.delete(); // 删除目录
file1.mkdir();//创建多级目录建议使用mkdirs();
String str[] = file1.list();//列出所有文件名
for (String string : str) {
System.out.println(string + " ");
}
File file2[];
file2 = File.listRoots();//列出系统盘符
for (File string : file2) {
System.out.println(string + " ");
}
file2 = file.listFiles();//列出虽有文件夹名和文件名
for (File string : file2) {
System.out.println(string + " ");
}
}
输入和输出(IO)
为什么程序需要IO?
案例一: 打游戏操作,得分比较高,储存游戏的信息(XXX-888分).
此时需要把游戏中的数据储存起来,只能储存在文件中.
案例二:打游戏操作,查看游戏排行榜.排行榜的数据储存在一个文件中的.
此时游戏程序需要去读取文件中的数据,并显示在游戏中.
案例三:上传和下载操作.
-----------------------------
IO操作是一个相对的过程.一般的我们站在程序角度思考(程序的内存)
程序需要数据:把数据流入到程序中,输入
程序需要保存数据,在把数据传递
O流的分类和操作模板:
IO流的分类:站在不同的角度,分流方式是不一样的
1):根据流向划分: 输入流和输出流.
2):根据数据的单位划分: 字节流和字符流.
3):根据功能不同的划分: 节点流和包装流.
---------------------------------------------------------------
四大基流(字节输出流(Writer),字节输入流(Reader),字符输出流(OutputStream).字符输入流(InputStream))
四大基流都是抽象类:其他流都是继承与这四大基流.
我们不能创建四大基流的对象,只能创建其子类对象
无论是什么流,都有close方法,用来关闭资源
如果操作文件,就得开通一个流对象关联我们的磁盘文件,如果不关闭资源,那么磁盘的文件一直被程序所引用.
操作IO流的模板:
1):创建源或者目标对象(挖井)
拿文件流距离
输入操作:把文件中的数据流向到程序中,此时文件是源,程序是目标
输出操作:把程序中的数据流向到文件中,此时程序是源,文件是目标.
2):创建IO流对象(接水管)
输入操作:创建输入流对象
输出操作:创建输出流对象;
3):具体的IO操作(传输):
输入操作:输入流对象的read 方法
输出操作:输出流对象的write方法
4):关闭资源(关闭):
输入操作:输入流对象的close方法
输出操作:输出流对象的close方法
操作IO流的六字箴言:
读进来,写出去.
读进来:进来强调的是输入,说明是read()方法
写出去:出去强调的是输出,说明是write方法
文件流
程序跟文件打交道
此时的文件指的是纯文本文件.txt(笔记本那种,不要使用Word Excel)
-----------------------------------------------
FileInputStream 文件的字节读取流:
import java.io.File; import java.io.FileOutputStream; /** public static void main(String[] args) throws Exception { } |
FileOutputStream 文件的字节写入流
import java.io.File; /** public static void main(String[] args) throws Exception { } |
利用字节流完成文件的拷贝操作:
正确关闭资源和处理异常的代码:
Java 1.7以前:
java1.7(含)以后 自动资源关闭(推荐)
获取进程数据,编译和运行java代码
import java.io.File; /** |
文件字符流
FileReader 文件的字符读取流
import java.io.File; /** public static void main(String[] args) { try ( //创建读取流对象 } |
FileWriter 文件的字符写入流
import java.io.File; /** public static void main(String[] args) { } |
文件拷贝
import java.io.File; /** |
使用字节流操作汉子或特殊符号的时候,容易乱码,建议使用字符流
先有字节流,后又字符流,字符流是对字节流的补充
二进制文件:使用记事本打开某个文件,可以看到内容的就是文本文件,否则可以理解为二进制.
一般的操作,二进制文件必须使用字节流.
一般的,操作文本文件,使用字符流.
字符的解码和编码操作
编码: 把字符串转换成byte数组
解码: 把byte数组转换成字符串
一定要保证编码和解码的字符相同,否则乱码
包装流和缓冲流
处理流/包装流(相对于节点流更高级):
1:隐藏了底层的节点流的差异,并对外提供了更方便的输入/输出功能,让我们只关心高级流的操作.
2:使用处理流包装了节点流,程序直接操作处理流,让节点流雨底层的设备做IO操作.
3.只需要关闭处理流即可.
包装流如何区分:写代码的时候,发现创建对象的时候,需要创建另一个流对象.
new 包装流(流对象);
--------------------------------------------
缓冲流:
定义:是一个包装流,目的是起缓冲作用.
Sun提供的缓冲区:大小是:8192(1024*8),我们一般不用提升大小,使用默认.
BufferedInputStream:
BufferedOutputStream;
BufferedReader;
BufferedWriter;
目的:
操作流的时候,习惯定义一个byte/char数组,该数组其实就是一个缓冲区.
Int read();每次都从磁盘文件中读取一个字节,直接操作磁盘文件,性能极低.
解决方案:定义一个数组作为缓冲区.
Byte/char [] a = new byte/char[1024];该数组其实就是一个缓冲区,一次性从磁盘文件中读取1024个字节,如此一来,操作磁盘文件的次数少了,性能得以提升.
实际操作:
使用缓冲流跟未使用缓冲流的比较
转换流
转换流:把字节流转换成字符流
InputStreamReader : 把字节输入流转换成字符输入流
OutputStreamWriter : 把字节读取流转成字符读取流
内存流(储存数据)
字节内存流(安卓会用到):
字符内存流(基本不用)
字符串流
StringWriter 字符串的写入流
StringReader 字符串的读取流
对象流(序列化和反序列化)-服务器做的
以后对于我们需要共享数据的类也必须实现Serializable接口.
一些属性出于安全考虑,不应该被序列化,如:密码 解决的办法是该属性使用transient修饰.
使用对象流来完成序列化和反序列化操作:
ObjectOutputStream 通过writeObject方法做序列化操作.
ObjectInputStream 通过readObject方法做反序列化操作.
序列化的细节,序列化的版本:
1);如果某些数据不需要做序列化,那么此时该怎么做?
理论上说:静态的字段和瞬态的字段是不能做序列化操作的.
transient 修饰的成员.
2):序列化的版本问题:
反序列化java对象时,必须提供该对象的class文件,现在问题是:随着项目的升级,系统的class文件也会升级(增加/删除一个字段).
如何保证两个class文件的兼容性? java通过seriaIversionUID(序列版本号)
打印流(写入)
PrintStream 字节打印流
PrintWrite 字符打印流
-对于PrintWrite来说,
PrintWriter writer = new PrintWriter(new FileOutputStream("add.txt"),true);
启用了自动刷新,则只有在调用 println、printf 或 format 的其中一个方法时便会立马刷新操作.
如果没有开启自动刷新,则需要手动刷新,或者当缓存区满的时候,在自动刷新.
使用打印流作为输出流,此时的输出操作会特别简单,因为在打印流中:
提供了print方法,打印不换行
提供了println方法,打印在换行.
这两个方法支持打印各种数据类型的数据.因为参数为(Object t);
打印流中的格式化输出(printf方法):
二进制文件的读取操作
DataInputStream 读取二进制文件
DataOutputStream 写入二进制文件
标准的输入输出:
在system类中,有两个常量:
InputStream in = System.in; “标准”输入流.
PrintStream out = System.out;
标准流的重定向操作:
重新定制输入的方向不再是键盘,而是一个文件.
static void setIn(InputStream in)重新分配“标准”输入流。
此后,System.in的=数据的来源就是通过setIn指定的源.
Properties类加载文件
配置文件:资源文件(以properties作为拓展名的文件)/属性文件:
做项目开发,为何要使用配置文件?
把所有的数据储存在代码中,写死了,”硬性编码”;
比如:在java中需要连接数据库,必须拥有数据的账号和密码.
此时我们就得在java代码中编写类似的代码:
String ID = “Admin”;
String password = “asdfghjkl@16,#5”;
代码程序运行OK
但是,以后我们把项目部署在别人电脑/服务器中,别人电脑中的数据库的账号密码可以不再是Admin和asdfghjkl@16,#5,此时我们就得去项目中导出去找使用了行号密码的地方.
部署项目的是实施人员,为了安全操作,不能让其直接修改代码.
此时,我们专门为数据库提供了一个配置文件,里面专门储存数据库连接相关的信息
-------------------------------------------------------------
Db.properties
-------------------------------------------------------
#key = value;
ID = Admin
Password = asdfghjkl@16,#5
..........
---------------------------------------------------------
现在数据库的连接信息在db.properties文件中,而java代码需要获取该文件中的信息
重心转移:java代码如何加载properties文件,如何获取该文件中的数据
必须使用properties类 Hastable 的子类,Map借口的实现类.
随机访问文件
随机访问文件(RandomAccessFile):表示看在该文件的任何位置写入和读取数据.
管道流(了解)