流是一个抽象、动态的概念,是一连串连续动态的数据集合。
对于输入流而言,数据源就像水箱,流(stream)就像水管中流动着的水流,程序就是我们最终的用户。我们通过流(A Stream)将数据源(Source)中的数据(information)输送到程序(Program)中。
对于输出流而言,目标数据源就是目的地(dest),我们通过流(A Stream)将程序(Program)中的数据(information)输送到目的数据源(dest)中。
输入/输出流的划分是相对程序而言的,并不是相对数据源。
1.按流的方向分类:
节点流处于IO操作的第一线,所有操作必须通过它们进行;处理流可以对节点流进行包装,提高性能或提高程序的灵活性
File类是对文件系统中文件以及文件夹进行封装的对象,可以通过对象的思想来操作文件和文件夹。 File类保存文件或目录的各种元数据信息,包括文件名、文件长度、最后修改时间、是否可读、获取当前文件的路径名,判断指定文件是否存在、获得当前目录中的文件列表,创建、删除文件和目录等方法。
要想实现IO的操作,就必须知道硬盘上文件的表现形式,而java中就提供了一个File类。
构造方法:
public File(String pathname):根据一个路径得到一个File对象
File(String parent, String child) : 根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。
File(File parent, String child) : 根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。
方式一:File file1 = new File(“e:\\demo\\test.txt”);
方式二:File file2 = new File(“e:\\demo”,”test.txt”);
方式三:File file3 = new File(“e:\\demo”);
File file4 = new File(file3,”test.txt”);
注意:以上三种方式其实效果一样
创建功能: boolean mkdir():创建文件夹,如果存在此文件夹,则不创建,返回结果为false;
boolean createNewFile():创建文件,如果此文件存在,则不创建,返回结果为false;
注意:如果需要在某个文件夹下创建文件,则此文件依赖的文件夹必须存在,否则会出现IO异常,系统找不到指定路径。
如果创建文件或文件夹时忘记写盘符路径,默认在项目路径下。
boolean mkdirs():用于创建文件夹,如果父文件夹不存在时,其可以自动创建父文件夹,即用于创建多级文件的。
例如:
File file = new File(“e:\\test\\test.txt”);
System.out.println(“mkdir:”+file.mkdirs());
以上两行代码执行正确。
public boolean delete();此方法可以删除文件或文件夹。
注意:java中的删除不走回收站;
被删除文件夹中不能包含子文件或文件夹
public boolean isDirectory();判断是否是目录
public boolean isFile();判断是否是文件
public boolean exists();判断是否存在
public boolean canWrite();判断是否可写
public boolean canRead();判断是否可读
public boolean isHidden();判断是否隐藏
public boolean renameTo(File file);
如果路径名相同,改名,如果路径名不同,相当于改名并剪切
注意:路径以盘符开始:绝对路径
路径不以盘符开始:相对路径
需求:使用程序修改某个文件的名称。
File file = new File(“xxx.txt”);
File newFile = new File(“test.txt”);
System.out.println(“renameTo:”+ file.renameTo(newFile));
File file2 = new File(“xxx.txt”);
File newFile2 = new File(“e:\\test.txt”);
System.out.println(“renameTo:”+ file2.renameTo(newFile2));
获取功能:
public String getAbsolutePath();获取绝对路径
public String getPath();获取相对路径
public String getName();获取名称
public long length();获取长度,字节数
public long lastModified();获取最后一次的修改时间,毫秒值
public String[] list():获取指定目录下的所有文件或者文件夹的名称数组
public file[] listFiles(): 获取指定目录下的所有文件或者文件夹的File数组
InputStream 是所有的输入字节流的父类,它是一个抽象类。
ByteArrayInputStream、StringBufferInputStream、FileInputStream
是三种基本的介质流,它们分别从Byte 数组、StringBuffer、和本地文件中读取数据。PipedInputStream
是从与其它线程共用的管道中读取数据,与Piped 相关的知识后续单独介绍。 ObjectInputStream
和所有FilterInputStream 的子类都是装饰流(装饰器模式的主角)。
为了保证出现异常后流的正常关闭,通常要将流的关闭语句要放到finally语句块中,并且要判断流是不是null
OutputStream 是所有的输出字节流的父类,它是一个抽象类。
ByteArrayOutputStream、FileOutputStream 是两种基本的介质流,它们分别向Byte
数组、和本地文件中写入数据。PipedOutputStream 是向与其它线程共用的管道中写入数据, ObjectOutputStream
和所有FilterOutputStream 的子类都是装饰流。
3.字节流的输入与输出的对应
构造方法: FileInputStream(File file) FileInputStream(String name) 成员方法:
int read()从该输入流读取一个字节的数据。 int
read(byte[]b)从该输入流读取最多b.length个字节的数据到一个字节数组。 int
read(byte[]b,intoff,intlen)从该输入流读取最多len个字节的数据到字节数组。
//需求:使用字节输入流将文件中的内容读取并在控制台输出
//目标文件对象
File file = new File("d:\\test.txt");
// //创建输入流对象
FileInputStream fis=new FileInputStream(file);
//
// FileInputStream fis =new FileInputStream("d:\\test.txt");
byte [] b =new byte[(int)file.length()];
//读取内容
System.out.println( fis.read(b));
for (int i=0;i<b.length;i++){
System.out.print((char)b[i]);
}
//释放资源
fis.close();
}
FileOutputStream 的构造方法
public FileOutputSteam(File file);
public FileOutputSteam(String name);
public FileOutputSteam(String name,boolean append);
成员方法:
void write(byte[] b) 将 b.length字节从指定的字节数组写入此输出流。
void write(byte[] b, int off, int len) 从指定的字节数组写入 len字节,从偏移量
off开始输出到此输出流。void write(int b) 将指定的字节写入此输出流。
void close() 关闭此输出流并释放与此流相关联的任何系统资源。
//指定输出内容的文件
// File file = new File("d:\\test.txt");
//创建输出流的对象
// OutputStream os=new FileOutputStream(file);
/**
* A;创建File对象
* B:新建文件
* C:写出内容
*/
OutputStream os =new FileOutputStream("d:\\test.txt");
//准备输出的内容
String str = "Hello io";
//将输出内容按字节方式进行输出
// os.write(str.getBytes());
os.write(str.getBytes(),0,4);//0表示起始
os.close();
在上面的继承关系图中可以看出:
Reader 是所有的输入字符流的父类,它是一个抽象类。
CharReader、StringReader是两种基本的介质流,它们分别将Char 数组、String中读取数据。PipedReader 是从与其它线程共用的管道中读取数据。
BufferedReader 很明显就是一个装饰器,它和其子类负责装饰其它Reader 对象。
FilterReader是所有自定义具体装饰流的父类,其子类PushbackReader 对Reader 对象进行装饰,会增加一个行号。
InputStreamReader 是一个连接字节流和字符流的桥梁,它将字节流转变为字符流。
FileReader 可以说是一个达到此功能、常用的工具类,在其源代码中明显使用了将FileInputStream 转变为Reader的方法。我们可以从这个类中得到一定的技巧。
Reader 中各个类的用途和使用方法基本和InputStream中的类使用一致。后面会有Reader 与InputStream 的对应关系。
基类:Reader 抽象类
子类:InputStreamReder
构造方法:
按系统默认字符集进行文件内容的读取
InputStreamReader(InputStream in) 创建一个使用默认字符集的InputStreamReader。
按指定字符集进行文件内容的读取
InputStreamReader(InputStream in, String charsetName) 创建一个使用命名字符集的
File file =new File("d:\\\\test.txt");
//构造InputStream对象
InputStream is = new FileInputStream("d:\\\\test.txt");
//创建字符输入流对象
InputStreamReader isr= new InputStreamReader(is);
//读取内容
// int b = -1;
// while ((b=isr.read())!=-1){
// System.out.print((char)b);
// }
//创建存储的缓冲区
char [] chs = new char [(int)file.length()];
//将文件内容读取到缓冲区chs
isr.read(chs);
for (char c:chs
) {
System.out.print(c);
}
//释放资源
isr.close();
is.close();
在上面的关系图中可以看出:
Writer 是所有的输出字符流的父类,它是一个抽象类。 CharArrayWriter、StringWriter
是两种基本的介质流,它们分别向Char 数组、String 中写入数据。PipedWriter 是向与其它线程共用的管道中写入数据,
BufferedWriter 是一个装饰器为Writer 提供缓冲功能。 PrintWriter 和PrintStream
极其类似,功能和使用也非常相似。
OutputStreamWriter 是OutputStream 到Writer 转换的桥梁,它的子类FileWriter 其实就是一个实现此功能的具体类(具体可以研究一SourceCode)。功能和使用和OutputStream 极其类似,后面会有它们的对应图。
字符输出流:Writer抽象类
子类:OutputStreamWriter
构造方法
OutputStreamWriter(OutputStream out) 创建一个使用默认字符编码的OutputStreamWriter。
OutputStreamWriter(OutputStream out, String charsetName) 创建一个使用命名字符集的OutputStreamWriter。
成员方法:
void write(char[] cbuf, int off, int len) 写入字符数组的一部分。
void write(int c) 写一个字符
void write(String str, int off, int len) 写一个字符串的一部分
//创建字符输出流对象,并指定转储文件
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\\\\pet.template"),"utf-8");
String info = "您好,我的名字是{name},我是一只{type},我的主人{master}";
//写出操作
osw.write(info);
osw.close();
FileWriter:字符输出流的便捷类,也是OutputStreamWriter的子类
构造方法:
FileWriter(File file) 给一个File对象构造一个FileWriter对象。
FileWriter(File file, boolean append) 给一个File对象构造一个FileWriter对象。
FileWriter(String fileName) 构造一个给定文件名的FileWriter对象。
FileWriter(String fileName, boolean append) 构造一个FileWriter对象,给出一个带有布尔值的文件名,表示是否附加写入的数据。
成员方法:
public void flush();
public void close();
void write(char[] cbuf, int off, int len) 写入字符数组的一部分。
void write(int c) 写一个字符
void write(String str, int off, int len) 写一个字符串的一部分
转换流的特点:
何时使用转换流?
具体的对象体现:
该对象并不是流体系中的一员,其封装了字节流,同时还封装了一个缓冲区(字符数组),通过内部的指针来操作字符数组中的数据。 该对象特点:
注意:该对象在实例化时,如果要操作的文件不存在,会自动创建;如果文件存在,写数据未指定位置,会从头开始写,即覆盖原有的内容。
可以用于多线程下载或多个线程同时写数据到文件。
经典代码:
1.使用流读取文件内容(经典代码,一定要掌握)
import java.io.*;
public class TestIO2 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("d:/a.txt"); // 内容是:abc
StringBuilder sb = new StringBuilder();
int temp = 0;
//当temp等于-1时,表示已经到了文件结尾,停止读取
while ((temp = fis.read()) != -1) {
sb.append((char) temp);
}
System.out.println(sb);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
//这种写法,保证了即使遇到异常情况,也会关闭流对象。
if (fis != null) {
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
为了保证出现异常后流的正常关闭,通常要将流的关闭语句要放到finally语句块中,并且要判断流是不是null。
2.利用文件流实现文件的复制
package d804_2;
import java.io.*;
public class IoDemo2 {
public static void main(String[] args) {
copyFile("d:\\p.txt","d:\\u2.txt");
}
static void copyFile(String src, String dec) {
FileInputStream fis = null;
FileOutputStream fos = null;
//为了提高效率,设置缓存数组!(读取的字节数据会暂存放到该字节数组)
byte[] buffer = new byte[1024];
int temp = 0;
try {
fis = new FileInputStream(src);
fos = new FileOutputStream(dec);
//边读边写
//temp指的是本次读取的真实长度,temp等于-1时表示读取结束
while ((temp = fis.read(buffer)) != -1) {
/*将缓存数组中的数据写入文件中,注意:写入的是读取的真实长度;
*如果使用fos.write(buffer)方法,那么写入的长度将会是1024,即缓存
*数组的长度*/
fos.write(buffer,0,temp);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fos != null) {
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fis != null) {
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}