File
- 介绍:IO包中唯一表示文件和目录的路径的对象的类。
- 特点:只能获取和设置文件本身的信息,不能获取和设置文件的内容。
- 功能:创建、删除、重命名、查询状态、判断类型等
- 路径分隔符
String pathSeparator = File.pathSeparator();//不常用
Windows:"\","/"
Unix:"/" - 属性分隔符
String separator = File.separator();
Windows:";"
Unix:":" - 注意:
Unix严格区分大小写,Windows默认情况下不区分大小写。
Java中"\“是转义字符,如果使用”\“需要写为”\\",但是因为两种系统都支持"/“的写法,故通常使用”/"。
需求:列出指定目录的所有文件。
public void listAllFile(File file){
File[] files = file.listFiles();//列出该目录的所有File对象
for(File f : files){
System.out.println(f);
if(f.isDirectory())//如果该File是目录,递归查看File子目录
listAllFile(f);
}
}
FilenameFilter(文件过滤器)
需求:得到指定目录下所有以.java结尾的文件。
public File[] fileFilter(File file){
File[] files = file.listFiles(new FilenameFilter(){//文件过滤器
public boolean accept(File dir,String name){
return new File(dir,name).isFile() && name.endWith(".java");
}
});
return files;
}
IO流
四大基流
四大基流都是抽象类,其他流都是基流的实现类。
文件流
文件字节输入流:FileInputStream
文件字节输出流:FileOutputStream new FileOutputStream(file,true);//表示文件追加
文件字符输入流:FileReader
文件字符输出流:FileWriter new FileWriter(file,true);//表示文件追加
注意:
1、不要用字节流来处理字符。
2、String类中getBytes()方法可以把字符串转为byte数组。
3、关于flush()方法,字符流都有用,字节流只有缓冲流有用。
4、输入输出都应当使用字节/字符缓冲数组
缓冲流
字节缓冲输入流:BufferedInputStream
字节缓冲输出流:BufferedOUtputStream
字符缓冲输入流:BufferedReader
字符缓冲输出流:BufferedWriter
优点:
1、缓冲流比节点流效率高
2、有机会回滚写入的数据
注意:
1、默认缓冲区大小8192(8*1024)
转换流
InputStreamReader:把字节输入流转换为字符输入流
OutputStreamWriter:把字节输出流转换为字符输出流
问题:为什么有字节转换流没有字符转换流?因为字符流是字节流的增强,操作文本时字符流更为有效。
打印流
字节打印流:PrintStream
字符打印流:PrintWriter
注意:PrintWriter可以启用自动刷新。
new PrintWriter(new FileOutputStream(file),true);
启用自动刷新之后,调用println、printf、format方法才有效。
对象流(序列化和反序列化)
序列化:把内存中的对象数据存储到磁盘文件或在网络上传输
ObjectInputStream
反序列化:把磁盘文件或在网络上传输的数据解析成内存中的数据ObjectOutputStream
注意:如果抛NotSerializableException,表示序列化的对象没有实现Serializable接口。
需要做序列化的对象的类,必须实现序列化接口:java.io.Serializable接口(标志接口[没有抽象方法]).
底层会判断,如果当前对象是Serializable的实例,才允许做序列化.对象 instanceof Serializable;
问题
1、为什么需要序列化?
1):分布式系统中,需要共享的JavaBean对象,得做序列化后在网络上传输。
2):服务钝化:发现某些对象很久没有活动,服务器会把这些对象,持久化在本地磁盘文件。
2、如果某些数据不需要序列化(如:密码),怎么办?
transient String password;//瞬态字段
3、反序列化时需要提供对象的class文件,但class文件可能会变化(增加新的字段),如何保证版本兼容问题?
如果不显示定义serialVersionUID变量,该变量的值由JVM根据类相关信息计算,而修改后的类和之前不同,所以会出现不兼容问题(InvalidClassException)。解决方法是在类中提供一个固定的serialVersionUID。private static final long serialVersionUID = 1L
随意访问文件(RandomAccessFile)
常使用于多线程下载和断点下载
RandomAccessFile raf = new RandomAccessFile(file,rw);
//rw:以读写方式打开
//r:以只读方式打开(调用write方法抛出IOException)
raf.seek(0);//设置文件指针为第0个字节
raf.skipBytes(12);//设置文件指针跳过12个字节
管道流
实现两个线程之间的数据交互.
PipedInputStream
PipedOutputStream
PipedReder
PipedWriter
class OutputThread extends Thread{
private PipedOutputStream out = new PipedOutputStream();
public PipedOutputStream getOut(){
return out;
}
public void run(){
//TODO
}
}
class InputThread extends Thread{
private PipedInputStream in = null;
public InputThread(PipedOutputStream out){
in = new PipedInputStream(out);
}
public void run(){
//TODO
}
}
class Test{
public static void main(String[] args){
OutputThread outThread = new OutputThread();
InputThread inThread = new InputThread(outThread.getOut());
outThread.start();
inThread.start();
}
}
内存流(数组流)
字节内存流:ByteArrayInputStream、ByteArrayOutputStream
字符内存流:CharArrayInputStream、CharArrayOutputStream
字符串流:StringReader、StringWriter
合并流
SequenceInputStream(InputStream in,InputStream otherIn)
标准流的重定向
System.setIn(InputStream in);//修改System.in的源
System.setOut(OutputStream out);//修改System.out的目标
NIO
Properties类加载文件
Properties类(Hashtable的子类,Map的实现类)
Properties p = new Properties();
ClassLoader loader = Thread.currentThread().getContextClassLoader();//得到类加载器,相对路径为bin目录
InputStream inStream = loader.getResourceAsStream("db.properties");
p.load(inStream);
问题:为什么使用配置文件?
防止硬编码,让维护人员不修改源代码也能修改相关信息。(如:数据库连接相关信息)
资源的正确关闭方式
java1.7之前
public void closeStream(File srcFile,File destFile){
InputStream in = null;
OutputStream out = null;
try{
in = new FileInputStream(srcFile);
out = new FileOutputStream(destFile);
//TODO
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(in != null)
in.close();
}catch(Exception e){
e.printStackTrace();
}
try{
if(out != null)
out.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
//1、将声明放在try外边是因为finally中需要关闭
//2、finally中的判空是防止出现异常时out对象还未实例化导致finally中的close方法出现空指针异常问题。
//3、finally中两个try是防止关闭in时出现异常导致out对象无法关闭
java1.7之后
public void closeStream(File srcFile,File destFile){
try(
InputStream in = new FileInputStream(srcFile);
OutputStream out = new FileOutputStream(destFile);
){
//TODO
}catch(Exception e){
e.printStackTrace();
}
}
字符编码
常见字符集:ASCII、ISO-8859-1、GB2312\GBK\GB18030、ANSI、UTF-8、UTF-8 BOM
ISO-8859-1:占一个字节,收录了西欧语言,不能表示汉字
GB2312\GBK\GB18030:占两个字节,支持中文
ANSI:占两个字节,在简体中文操作系统中ANSI就是GB2312
UTF-8:针对Unicode的可变长字符编码
UTF-8 BOM:微软搞出来的编码,空文本也占3个字节,不适用此编码。
注意:
1、建议使用UTF-8。
2、存储字母和数字,所有编码都只占一个字节。
3、存储中文,GBK家族占两个字节,UTF-8占3个字节。
编码和解码
byte[] bytes = "hello".getBytes("UTF-8");
new String(bytes,"UTF-8");