InputStream:字节输入流
OutputStream:字节输出流
Reader:字符输入流
Writer:字符输出流
当一个流的构造方法中需要一个流的时候,这个被传进来的流叫做节点流,外部包装这个流的叫做包装流(处理流),关闭时只需关闭最外层包装流就行。
所有的流都实现了Closeable接口,都是可关闭的,用完流之后一定要关闭资源;所有的输出流都实现了Flushable接口,输出流在最终输出之后,一定要记得flush()刷新一下,清空管道。
java.io包下需要掌握的流有16个:
文件专属
FileInputStream;
FileOutputStream;
FileReader;
FileWriter;
转换流
InputStreamReader;
OutputStreamWriter;
缓冲流(有缓冲区)
BufferedInputStream;
BufferedOutputStream;
BufferedReader;
BufferedWriter;
数据流(可以对文件操作不同的数据类型)
DataInputStream;
DataOutputStream;
标准输出流(PrintStream(File file) 使用指定的文件创建一个新的打印流,而不需要自动换行, 与其他输出流不同, PrintStream从不抛出IOException)
PrintStream;
PrintWriter;
对象专属流:(序列化与反序列化)
ObjectInputStream;
ObjectOutputStream;
文件的各种方法
public boolean exists();测试此抽象路径名表示的文件或目录是否存在。
public boolean isFile();测试此抽象路径名表示的文件是否是一个标准文件。
public boolean isDirectory();测试此抽象路径名表示的文件是否是一个目录。
public boolean isHidden();测试此抽象路径名指定的文件是否是一个隐藏文件。
public boolean isAbsolute();测试此抽象路径名是否为绝对路径名
public String getName();返回由此抽象路径名表示的文件或目录的名称。该名称是路径名名称序列中的最后一个名称。如果路径名名称序列为空,则返回空字符串。
public String getPath();将此抽象路径名转换为一个路径名字符串。
public String getParent();返回此抽象路径名父目录的路径名字符串;如果此路径名没有指定父目录,则返回 null。
public String getAbsolutePath();返回此抽象路径名的绝对路径名字符串。
public long lastModified();返回此抽象路径名表示的文件最后一次被修改的时间
创建文件
//File(String pathname) 通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例
File file = new File("C:\\715\\a.txt");
//创建文件
file.createNewFile();
//File(String parent, String child) 从父路径名字符串和子路径名字符串创建新的 File实例
String parent = "C:\\715";
String child = "b.txt";
File file2 = new File(parent,child);
//第3种
File file3 = new File(parent,"c.txt");
创建文件夹
//根据给定的路径名创建一个新的文件夹实例
File file = new File("c:\\715\\test");
//判断该文件夹是否存在
System.out.println("test是否存在 " + file.exists());
//创建文件夹
file.mkdir();
System.out.println("---------mkdir()与mkdirs()区别");
File file2 = new File("c:\\715\\test2\\test3");
//创建文件夹
file2.mkdir();
System.out.println("********************");
System.out.println("---------mkdir()与mkdirs()区别");
File file3 = new File("c:\\715\\test2\\test3");
//创建文件夹
file3.mkdirs();//能创建连续目录
删除文件或文件夹
//构造一个文件对象实例
File file = new File("c:\\715\\test");
//删除test2目录 如果该路径下还有文件或文件夹,不能删除成功
boolean result = file.delete();
System.out.println("删除是否成功:" + result);
//public void deleteOnExit();在虚拟机终止时,请求删除此抽象路径名表示的文件或目录
//file.deleteOnExit();
获取文件列表
File file = new File("D:\\");
//获取所有文件路径
File[] files = file.listFiles();
for(File f:files) {
System.out.println("文件:" + f);
}
System.out.println("*****************************");
//获取文件名字符串
String[] fs = file.list();
for(String s:fs) {
System.out.println(s);
}
运用递归输出文件夹里所有文件
File file = new File("C:\\715\\io\\day1\\io");
//定义长度变量
digui(file);
}
//递归的层次不要太多,否则容易引起内存溢出
private static void digui(File file) {
//获取所有的文件
File[] files = file.listFiles();
//循环中判断
for(File f:files) {
System.out.println(f.getName() + (f.isDirectory() ? "是文件夹": "是文件"));
//判断
if(f.isDirectory()) {
//继续调用digui这个方法
digui(f);
}
}
}
对文件夹进行过滤
//对文件夹内的文件进行过滤
File file = new File("C:\\715\\io\\day1\\io\\src\\com\\gec\\file");
//只需要.java文件
// FilenameFilter:文件过滤器,需要重写方法
File[] files = file.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".java");
}
});
for(File f:files) {
System.out.println("文件名:" + f.getName());
}
往记事本中写入数据
方法:
void close() 关闭此输出流并释放与此流相关联的任何系统资源。
void flush() 刷新此输出流并强制任何缓冲的输出字节被写出。
void write(byte[] b) 将 b.length字节从指定的字节数组写入此输出流。
void write(byte[] b, int off, int len) 从指定的字节数组写入 len个字节,从偏移 off开始输出到此输出流。
abstract void write(int b) 将指定的字节写入此输出流。
File file = new File("C:\\715\\b.txt");
//判断文件是否存在,不存在就创建
if(!file.exists()) {
file.createNewFile();
}
OutputStream out = null;
try {
//支持追加字符,默认是false
out = new FileOutputStream(file,true);
//调用写的方法
/*
out.write(97);
out.write(98);
out.write(99);
*/
byte[] b = new byte[] {97,98,99,100,101};
out.write(b);
String str = "你会找到一个比我更好的";
out.write(str.getBytes());
System.out.println("写好了");
} catch (Exception e) {
e.printStackTrace();
}finally {
if(out != null) {
out.close();
}
}
利用文件通道读写文件
//写
File file = new File("c:\\715\\aa.txt");
//利用通道
try(FileOutputStream fos = new FileOutputStream(file)){
//文件通道
FileChannel fc = fos.getChannel();
//定义容量
ByteBuffer buff = ByteBuffer.allocate(1024);
//定义一个数组
byte[] b = new byte[] {65,66,67,68};
//循环存储
for(int i = 0;i < b.length;i++) {
//存数据
buff.put(b[i]);
}
//反转(一定要反转)
buff.flip();
//把缓冲的数据写入通道
fc.write(buff);
System.out.println("ok");
}
//读
File file = new File("c:\\715\\aa.txt");
try(FileInputStream fis = new FileInputStream(file)){
//获取文件通道
FileChannel fc = fis.getChannel();
//创建一个缓冲
ByteBuffer buff = ByteBuffer.allocate(1024);
//从文件通道中取到的顺序字节,然后放到定义好的缓冲里面
fc.read(buff);
//反转
buff.flip();
while(buff.hasRemaining()) {
byte b = buff.get();
System.out.println((char)b);
}
}
读取当前文件内容并写到其他地方
File source = new File("C:\\715\\b.txt");
File target = new File("C:\\715\\T.txt");
//判断
if(!target.exists()) {
target.createNewFile();
}
try(InputStream is = new FileInputStream(source);
OutputStream out = new FileOutputStream(target);
) {
//定义一个缓冲数组
int hasread = 0;
byte[] b = new byte[1024];
while((hasread = is.read(b)) > 0) {
//要把读取到的多少个字节(b)转换为String,长度是hasread
out.write(b, 0, hasread);
}
} catch (Exception e) {
e.printStackTrace();
}
使用缓冲流读取数据
//不用再定义缓冲数组,自带缓冲
FileReader source = new FileReader("D:\\715\\b.txt");
FileInputStream fs = new FileInputStream("D:\\715\\b.txt");
//转换流,将字节流转为字符流
InputStreamReader is = new InputStreamReader(fs);
BufferedReader br1 = new BufferedReader(is);
BufferedReader br2 = new BufferedReader(source);
String s = null;
while ((s = br1.readLine())!=null){
System.out.println(s);
}
while ((s = br2.readLine())!=null){
System.out.println(s);
}
br1.close();
br2.close();
使用缓冲流写数据
FileWriter fw = new FileWriter("D:\\715\\cc.txt",true);
BufferedWriter out = new BufferedWriter(fw);
out.write("债转股");
out.write("\n");
out.write("回复俄方");
out.write(1213);
out.flush();
out.close();
字符输入流
//读取b.txt ,并打印到控制台
File file = new File("C:\\715\\b.txt");
//2字符输入流 读取字符用
Reader r = new FileReader(file);
//FileInputStream调用 read读取是一个字节
//Reader read读取的是一个字符
int hasread = 0;
while((hasread = r.read()) >0) {
System.out.print((char)hasread);//char强制转型成字符型
}
//关闭资源
r.close();
字符输出流
//跨平台写法 File.separator,相当于windows的\\和unix的/
File file = new File("C:" + File.separator + "715" + File.separator + "c.txt");
//判断文件是否存在
if(!file.exists()) {
file.createNewFile();
}
//操作字符实例
Writer w = new FileWriter(file);
//定义一个字符串
String str = "天气这么热,我哪里也不想去,只想呆在房间写代码";
//调用方法写出去
w.write(str);
System.out.println("写好了");
//关闭资源
w.close();
文件拷贝
IO的方式通常分为几种,同步阻塞的BIO、同步非阻塞的NIO、异步非阻塞的AIO。
BIO是一个连接一个线程。
NIO是一个请求一个线程。
AIO是一个有效请求一个线程。
BIO
public class test1 {
public static void main(String[] args) throws IOException {
File f3=new File("C:\\715");
File f4=new File("D:\\715");
// 如果文件夹不存在就创建
if (!f4.exists()) {
f4.mkdirs();
}
kaobei(f3,f4);
}
private static void kaobei(File f3, File f4) throws IOException {
//
if(!f4.exists()) {
f4.mkdirs();
}
//将文件遍历出来
File[] f5=f3.listFiles();
//循环
for(File f:f5) {
if(f.isDirectory()) {
//创建文件实例
File f6=new File(f3,f.getName());
File f7=new File(f4,f.getName());
//递归
kaobei(f6,f7);
}else {
try(FileInputStream fi=new FileInputStream(f);
FileOutputStream fo=new FileOutputStream(f4+File.separator+f.getName())
){
//管道
FileChannel fc1=fi.getChannel();
FileChannel fc2=fo.getChannel();
fc1.transferTo(0, fc1.size(), fc2);
}
}
}
System.out.println("成功");
}
}
AIO
public class test1 {
public static void main(String[] args) throws IOException {
File f3=new File("C:\\715");
File f4=new File("D:\\715");
//如果文件夹不存在就创建
if (!f4.exists()) {
f4.mkdirs();
}
kaobei(f3,f4);
}
private static void kaobei(File f3, File f4) throws IOException {
//
if (!f4.exists()) {
f4.mkdirs();
}
//将文件遍历出来
File[] f5 = f3.listFiles();
//循环
for (File f : f5) {
if (f.isDirectory()) {
//创建文件实例
File f6 = new File(f3, f.getName());
File f7 = new File(f4, f.getName());
//递归
kaobei(f6, f7);
} else {
try (InputStream fi = new FileInputStream(f);
OutputStream fo = new FileOutputStream(f4 + File.separator + f.getName())) {
//BIO使用管道,AIO使用byte数组
int len = 0;
byte[] b = new byte[1024];
while ((len = fi.read(b)) > 0) {
fo.write(b, 0, len);
}
}
}
}
}
}
NIO
File source = new File("c:\\715\\io\\2.rar");
File target = new File("c:\\715\\3.rar");
long start = System.currentTimeMillis();
try(FileInputStream fis = new FileInputStream(source);
FileOutputStream fos = new FileOutputStream(target)
){
//获得各自的文件通道
FileChannel fc = fis.getChannel();
FileChannel fo = fos.getChannel();
//0 表示索引的开始 ,fc.size:源文件的大小,fo:目标文件
fc.transferTo(0, fc.size(), fo);
}
long end = System.currentTimeMillis();
//耗时:374毫秒
System.out.println("耗时:" + (end -start) + "毫秒");
序列化与反序列化
序列化:将java对象存储到文件中
反序列化:将硬盘上的数据恢复到内存当中,恢复成java对象
也可以序列化多个对象,把对象放入集合中
class Human implements Serializable{
//一旦id生成,不要随便修改它!! 如果改了会发生 local class incompatible:
//stream classdesc serialVersionUID = 1, local class serialVersionUID = 1111
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Human(Integer id, String name) {
super();
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "Human [id=" + id + ", name=" + name + "]";
}
}
public class TestPerson {
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
File f = new File("C:\\715\\b.txt");
try(OutputStream os = new FileOutputStream(f);
ObjectOutputStream oos = new ObjectOutputStream(os)
){
Human h = new Human(1, "a");
/**
* 把内存中的对象(new Human)固化到硬盘上(user.dat)
*/
oos.writeObject(h.toString()));
oos.flush();
oos.close();
System.out.println("序列化对象完成");
}
//读取文件并反序列为内存中的对象
try(
InputStream is = new FileInputStream(f);
ObjectInputStream ois = new ObjectInputStream(is)
){
Object obj = ois.readObject();
System.out.println(obj);
ois.close();;
System.out.println("反序列化对象完成");
}
}
}
IO和Properties联合使用
类似于这种机制的文件被称为配置文件,建议以.properties结尾
FileReader fe = new FileReader("test01/src/userinfo.properties");
//Properties是一个Map集合
Properties po = new Properties();
//将userinfo文件中的数据加载到Properties对象当中
po.load(fe);
//通过key来获取
String username = po.getProperty("username");
System.out.println(username);