学习IO流之前先了解一下File类
File类
封装文件/目录的各种信息,对目录/文件进行操作,但是我们不可以获取到文件/目录中的内容
//将文件封装为一个File类的对象:
File f = new File("path+文件名");
//File.separator属性帮我们获取当前操作系统的路径拼接符号
//在windows,dos下,系统默认用“\”作为路径分隔符 ,在unix,url中,使用“/”作为路径分隔符。
因为不同的操作系统所以一般建议使用这种方式将文件封装为一个File对象
File f3 = new File("path"+File.separator+"文件名");
File的4种构造函数
new File(字符串的路径);
new File(uri);
new File(String parent, filename);
new File(File parent, filename);
######常用方法:
System.out.println("文件是否可读:" + f.canRead());
System.out.println("文件是否可写:" + f.canWrite());
System.out.println("文件的名字:" + f.getName());
System.out.println("上级目录:" + f.getParent());
System.out.println("是否是一个目录:" + f.isDirectory());
System.out.println("是否是一个文件:" + f.isFile());
System.out.println("是否隐藏:" + f.isHidden());
System.out.println("文件的大小:" + f.length());
System.out.println("是否存在:" + f.exists());
f.delete();//删除文件或目录
f.createNewFile();//创建文件
System.out.println("绝对路径:"+f.getAbsolutePath());
System.out.println("相对路径:"+f.getPath());
System.out.println("文件的大小:"+f.length());
f.mkdir();//创建单层目录
f.mkdirs();//创建多层目录
f.getFreeSpace();//剩余空间
f.getUsableSpace();//使用空间
f.getTotalSpace();//总空间
f.getParentFile();//获取父目录
f.isAbsolute();//是不是绝对路径
f.lastModified//返回所引用文件最后修改日期, 为自 1970年1月1日0:00 以来的毫秒数
list()方法 : 会返回一个字符数组,将制定路径下的文件或文件夹名字存储到String数组中。因为其返回的是一个String类型的数组
1)、String[] list()
2)、String[] list(FilenameFilter filter)
//list()的用法
path = new File("E:\\Java");
list = path.list();
for(String itemName : list){
System.out.println(itemName);
}
//FilenameFilter 过滤器,文件名称过滤器
String[] paths = file.list(new FilenameFilter() {
//使用匿名内部类
@Override
public boolean accept(File dir, String name) {
// 文件名称以java结尾的文件
if (name.endsWith("java")) {
return true;
}
return false;
}
});
//lambda表达式
String[] paths = file.list((File dir, String name) -> name.endsWith("java"));
总结:
创建:
createNewFile():在指定位置创建空文件,成功返回true,如果已存在就不再创建了返回false
mkdir():在指定位置创建目录,这之后创建最后一级目录,如果上级目录不存在就抛出异常.
mkdirs():在指定位置创建目录,这也会创建路径中所有不存在的父目录
renameTo(File dest):重命名文件或文件夹。文件不同时,相当于文件的剪切,剪切的时候不能操作非空文件夹。移动/重命名成功返回true,失败返回false
删除:
delete() :删除一个文件或者空文件夹,如果文件夹不为空,则不能删除,成返回true,失败返回false
deleteOnExit(): 在虚拟机终止时,请求删除此抽象路径名的文件或者目录,保证文件异常时也可以删除文件
判断:
exists():判断指定的文件或者文件夹是否存在
isFile():判断是否是一个文件;如果不存在,则为false
isDirectory():判断是否是一个文件夹
isHidden():判断指定的文件是否是隐藏文件
isAbsolute():判断指定的文件或文件夹是否是在绝对路径下
获取:
getName():获取文件或文件夹名称
getPath():返回的是绝对路径,可以是相对路径,但是目录要指定
getAbsolutePath():获取绝对路径
length():获取文件的大小(字节为单位)
getParent():获取文件的父路径
lastModified():获取文件最后一次修改的时间
注意:
. :一个点表示当前路径
… :两个点表示上一级路径
路径问题:
绝对路径:该文件在硬盘上的完整路径;绝对路径一般是以盘符开头的。
相对路径:资源文件相对于当前程序所在路径。
**注意:**如果程序当前所在路径与资源文件不再同一个盘下面,是没法写相对路径的
案例遍历磁盘:
public static void find(File file) {
if (file.isFile()) {
System.out.println(file.getAbsolutePath());
} else {
File[] fs = file.listFiles();
if (fs != null) {
for (File file2 : fs) {
find(file2);
}
}
}
}
private void scannerFile(String path) {
File file = new File(path);
String[] list = file.list();
for (String filename : list) {
String realPath = path + File.separator + filename;
File ff = new File(realPath);
if (ff.isFile()) {
System.out.println(ff.getAbsolutePath());
} else {
scannerFile(realPath);
}
}
}
private void scannerFile1(String path) {
File file = new File(path);
File[] list = file.listFiles();
for (File f : list) {
if (f.isFile()) {
System.out.println(f.getAbsolutePath());
} else {
scannerFile(f.getAbsolutePath());
}
}
}
字节流
InputStream:字节输入流基类,抽象类是表示字节输入流的所有类的超类。
OutputStream:字节输出流基类,抽象类是表示输出字节流的所有类的超类。
FileInputStream:字节文件输入流,从文件系统中的某个文件中获得输入字节,用于读取诸如图像数据之类的原始字节流。
FileOutputStream:字节文件输出流是用于将数据写入到File,从程序中写入到其他位置。
BufferedInputStream:字节缓冲输入流,提高了读取效率。
BufferedOutputStream:字节缓冲输出流,提高了写出效率。
// 创建输入流 --》 字节输入流
InputStream is = new FileInputStream(new File("path"));
byte[] buf = new byte[1024];
int len = -1;
while ((len = is.read(buf)) != -1) {
System.out.write(buf, 0, len);
}
//IO流,打开之后,必须关闭
if(is!=null){
is.close();
}
注意:IO流中有很多的异常要处理
案例文件的复制
@Test
void test4() {
// 文件拷贝
InputStream is = null;
OutputStream os = null;
try {
is = new FileInputStream("path1");
os = new FileOutputStream(new File("path2"));
byte[] buf = new byte[1024];
int len = -1;
while ((len = is.read(buf)) != -1) {
os.write(buf, 0, len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
BufferedInputStream和BufferedOutputStream的使用与FileInputStream和FileOutputStream类似
注意使用BufferedInputStream和BufferedOutputStream一定要关流
// 刷新缓冲区
bos.flush();
#####字符流
Reader:读取字符流的抽象类.
Writer:写入字符流的抽象类.
InputStreamReader:字节流转字符流,它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。
OutputStreamWriter:字节流转字符流。
BufferedReader:字符缓冲流,从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
BufferedWriter:字符缓冲流,将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
FileReader:InputStreamReader类的直接子类,用来读取字符文件的便捷类,使用默认字符编码。
FileWriter:OutputStreamWriter类的直接子类,用来写入字符文件的便捷类,使用默认字符编码。
注意字符流存在编码的
@Test
void test() {
FileReader fr = null;
try {
fr = new FileReader("path");
fr.read();
} catch (IOException e) {
e.printStackTrace();
}
try {
char[] buf = new char[1024];
int len = -1;
while ((len = fr.read(buf)) != -1) {
// 字符数组转换为字符串
String string = new String(buf, 0, len);
System.out.println(string);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Test
void test() {
FileWriter fw = null;
try {
fw = new FileWriter("path");
} catch (IOException e) {
e.printStackTrace();
}
String msg = "";
try {
fw.write(msg.toCharArray());
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Test
void test() {
BufferedWriter bw = null;
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader("path1"));
bw = new BufferedWriter(new FileWriter("path2"));
String s = null;
while ((s = br.readLine()) != null) {
// 解决换行问题
// 1、 bw.write(s+"\n");
// 2、
bw.write(s);
bw.newLine();
//3、PrintWriter使用里面的println()
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bw != null) {
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
readLine()一行一行的读数据
将字节流转换为字符流
br = new BufferedReader(new InputStreamReader(System.in));
equalsIgnoreCase(“exit”);以exit为真
#####数据流
数据流:用来操作基本数据类型和字符串的
DataInputStream:将文件中存储的基本数据类型和字符串 写入 内存的变量中
DataOutputStream: 将内存中的基本数据类型和字符串的变量 写出 文件中
FileOutputStream fos = new FileOutputStream(f);
DataOutputStream dos = new DataOutputStream(fos);
DataOutputStream dos = new DataOutputStream(new FileOutputStream(new File("path")));
dos.writeBoolean(false);
dos.writeDouble(6.9);
dos.writeInt(82);
写出的类型跟读入的类型 必须 要匹配!
#####对象流
ObjectInputStream:对象输入流,从磁盘等保存介质中读取已经保存的对象数据
ObjectOutputStream:将对象转换为数据,保存起来
在java中,如果要保存对象,必须序列化该对象
把内存中的Java对象转换成平台无关的二进制数据,从而允许把这种二进制数据持久地保存在磁盘上,或通过网络将这种二进制数据传输到另一个网络节点。----》序列化
当其它程序获取了这种二进制数据,就可以恢复成原来的Java对象。----》反序列化
通俗的讲
将我们能看懂的文件内容转换为我们看不懂的: ----》序列化
我们看不懂文件的内容,但是程序是可以看懂的,所以可以写一个程序读文件中内容:----》反序列化
你想要序列化的那个对象对应的类,必须要实现一个接口:
Serializable:接口内部,什么都没有,这种接口叫 标识接口。
起到标识作用,标识什么呢?只要实现这个接口的类的对象才能序列化,否则不可以。
public class Person implements Serializable {}
serialVersionUID:
凡是实现Serializable接口(标识接口)的类都有一个表示序列化版本标识符的静态常量:
private static final long serialVersionUID;
serialVersionUID用来表明类的不同版本间的兼容性。简言之,其目的是以序列化对象进行版本控制,有关各版本反序加化时是否兼容。
如果类没有显示定义这个静态变量,它的值是Java运行时环境根据类的内部细节自动生成的。若类的实例变量做了修改,serialVersionUID 可能发生变化。故建议,显式声明。
简单来说,Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。(InvalidCastException)
被序列化的类的内部的所有属性,必须是可序列化的 (基本数据类型都是可序列化的)
static,transient修饰的属性 不可以被序列化。
防止忘记关流,这个将会自动关流
JDK7 提供新特性:
try-resource
try(创建需要关闭对象的代码放在这儿){
} catch(Exception e) {
}