- 输入流指向源,程序通过read()方法从输入流中读取源中的数据
- 输出流指向数据要去的目的地,程序通过write()方法向输出流写入数据,传送到目的地
1. File类
File对象用来获取文件的信息,不涉及读写操作。
- 创建File对象的构造方法:
File(String filename)
File(String directoryPath, String filename)
File(File f,String filename)
其中,filename:文件名字;directoryPath:文件的路径;f:指定成一个目录的文件
1.1 文件的属性
自行查阅相关方法(书本p329)
1.2 目录
- 创建目录
调用方法public boolean mkdir()
创建一个目录,创建成功返回true,否则返回false(如果该目录已存在就返回false) - 列出目录中的文件
(1)public String [ ] list():以字符串形式返回目录下所有文件。
(2)public File [ ] listFiles():以File对象形式返回目录下所有文件。
有时需要列出指定类型的文件,如.java、.txt等扩展名的文件,用以下方法:
(3)public String [ ] list(FilenameFilter obj):以字符串形式返回目录下指定类型的所有文件。
(4)public File [ ] listFiles(FilenameFilter obj):以File对象形式返回目录下指定类型的所有文件。
上述FilenameFilter是个接口,用一个方法:
public boolean accept(File dir,String name)
1.3 文件的创建与删除
1.4 运行可执行文件
用Runtime类。首先声明一个对象:
Runtime ec;
然后用该类的getRuntime()静态方法创建这个对象
ec=Runtime.getRuntime();
ec可以调用exec(String command)方法打开本地机上的可执行文件或执行一个操作。
2. 文件字节流
2.1 文件字节输入流
- 创建文件字节输入流
FileInputSteam类创建的对象被称为文件字节输入流,该类是InputStream的子类。
创建对象的构造方法:
FileInputStream(String name)
FileInputStream(File file)
name和file指定的文件成为输入流的源。
注意:程序必须在try......catch语句中的try块部分创建输入流对象,catch块部分检测并处理异常
- 以字节为单位读文件
输入流调用read( )方法顺序地读取源中的单个字节数据,返回字节值,如果到源的末尾,返回-1.
read方法还有其他形式,可以把多个字节读到一个字节数组中:
int read(byte b[ ]) //从文件读取b.length个字节,存放在数组b中
int read(byte b[ ],int off, int len) //从文件读取len个字节,存放在数组b中,首字节的位置是off
这两个方法都返回实际读取的字节个数,如果到达文件的末尾,返回-1.
2.2 文件字节输出流
- 创建文件字节输出流
FileOutputSteam类创建的对象被称为文件字节输入流,该类是OutputStream的子类。
创建对象的构造方法:
FileOutputStream(String name)
FileOutputStream(File file)
参数name和file指定的文件称为输出流的目的地
注意:如果输出流指向的文件不存在,Java会创建该文件;如果指向的文件是已存在的文件,输出流将刷新该文件(使得文件的长度为0)
下列构造方法在创建输出流时,可以选择是否刷新文件:
FileOutputStream(String name ,boolean append)
FileOutputStream(File file, boolean append)
如果append 值取true,不刷新文件(若文件已存在),输出流的write方法从文件的末尾开始写入数据;否则刷新文件(若文件已存在)
- 以字节为单位写文件
继承了OutputStream的write(byte b[ ])方法,该方法特点是以字节为单位向文件写入数据。
public void write(byte b[ ])
:写b.length个字节到文件
public void write(byte b[ ], int off, int len)
:从数组b的off处开始写len个字节到文件中
2.3 关闭流
通过调用close()方法
3. 文件字符流
与字节流相对应的是的FileReader、FileWriter字符流,分别是Reader和Writer的子类,其构造方法分别如下:
FileReader(String filename)
FileReader(File filename)
FileWriter(String filename)
FileWriter(File filename)
字符流以字符为基本单位处理数据,二者常用方法如下:
- int read():从源中读取一个字符,返回一个整数,未读出字符返回-1
- int read(char b [ ] ):从源中读取b.length个字符到数组b中,返回实际读取的字符数目。若到达源的末尾,返回-1
- int read(char b [ ], int off, int len):从源中读取len个字符放到数组b中,off是存放的首位置,返回实际读取的字符数目。若到达源的末尾,返回-1
- void write():向文件写入一个字符
- void write(char b [ ] ):向文件写入一个字符数组
- void write(char b [ ], int off, int len):从数组b的off处开始取出len个字符写到文件
4. 缓冲流
BufferedReader类和BufferedWriter类创建的对象称为缓冲输入流、缓冲输出流。二者的源和目的地必须是字符输入流和字符输出流。因此具有更强的读写能力
4.1构造方法分别如下:
BufferedReader(Reader in)
BufferedWriter(Writer out)
BufferedReader流可以读取文本行,方法是readLine()。
4.2 创建对象
通过向BufferedReader传递一个Reader子类的对象(例如FileReader的实例)来创建一个BufferedReader对象,例如:
FileReader in1=new FileReader("1.txt");
BufferedReader in2=BufferedReader(in1);
然后in2流调用readLine()方法读取1.txt,例如:
String str=in2.readLine():
BufferedWriter流和FileWriter流的连接与上面类似。
另外,BufferedWriter流有自己独特的向文件写入一个回行符的方法:
newLine()
可以把缓冲流称为上层流,把它们指向的字符流称为底层流。底层字符输入流先将数据读入缓存,缓冲输入流在从缓存读取数据;缓冲输出流将数据写入缓存,底层字符输出流再将缓存中的数据写入目的地。
5. 随机流
功能更完善的RandomAccessFile类。不是InputStream和OutputStream的子类。
5.1 构造方法:
-
RandomAccessFile(Srting name, String mode)
:参数name是文件名字,给出流的源,也是流的目的地。参数mode取r(只读)或者rw(可读/写),决定流对文件的访问权利。 -
RandomAccessFile(File file, String mode)
:参数file是File对象,给出流的源,也是流的目的地。参数mode取r(只读)或者rw(可读/写),决定流对文件的访问权利。
5.2 其他方法:
-
seek(long a)
:用来定位流的读/写位置,参数a确定读写为止距离文件开头的字节个数 -
getFilePointer()
:获取流的当前读写位置
RandomAccessFile流的readLine()方法在读取含有非ASCII字符的文件(例如汉字)会出现乱码,需要把读取的字符串用ISO8859-1重新编码存放到byte数组中,然后用当前计算机的默认编码将该数组转化为字符串:
(1)读取字符串:String str=in.readLine();
(2)用ISO 8859—1重新编码:byte b[ ]=str.getBytes("ISO 8859-1");
(3)使用当前计算机的默认编码将字节数组转化为字符串:String content=new String(b);
注:如果计算机的默认编码是GB2312,那么String content=new String(b);
等同于String content =new String(b,"GB2312");
6. 数组流
6.1 字节数组流
6.1.1 字节数组输入流
构造方法:
-
ByteArrayInputStream(byte[ ] buf)
:该方法构造的字节数组流的源是参数buf指定的数组的全部字节单元 -
ByteArrayInputStream(byte[ ] buf, int off, int len)
:该方法构造的字节数组流的源是参数buf指定的数组从off处按顺序取len个字节单元
其他方法:
-
public int read()
:调用该方法顺序地从源中读出一个字节,返回读出的字节值 -
public int read(byte [ ] b,int off, int len)
:调用该方法读出len个字节,存放到数组b中,从数组b的off处开始存放,返回读出的字节个数,若未读出则返回-1
6.1.2字节数组输出流
构造方法:
-
ByteArrayOutputStream()
:该方法构造的流指向一个默认大小为32字节的缓冲区,容量会随情况自动增加 -
ByteArrayOutputStream(int size)
:缓冲区大小由参数size决定,容量会随情况自动增加
其他方法:
public void write(int b)
:调用该方法顺序地向缓冲区写入一字节
public void write(byte[ ] b,int off, int len)
:将数组b中从off处取len个字节写入缓冲区
6.2字符数组流
与字节数组流相对应,CharArrayReader类和CharArrayWriter类,分别使用字符数组作为流的源和目的地。
7. 数据流
DataInputStream和DataOutputStream类创建的对象叫数据输入流和数据输出流。这两个流读取数值时,不必关心数值应当是多少字节。
构造方法:
-
DataInputStream( InputStream in)
:创建的数据输入流指向参数in指定的底层输入流 -
DataOutputStream( OutputStream out)
:创建的数据输出流指向一个参数out指定的底层输出流
相关方法自行查阅
8. 对象流
ObjectInputStream类和ObjectOutputStream类分别是InputStream类和OutputStream类的子类。
对象输出流用writeObject(Object obj)方法将对象obj写入文件;对象输入流使用readObject()方法读取对象。
构造方法:
ObjectInputStream(InputStream in)
ObjectOutputStream(OutputStream out)
ObjectOutputStream指向一个输出流对象,当准备将对象写入文件时,先用OutputStream的子类创建一个输出流,例如:
FileOutputStream fileOut=new FileOutputStream("tom.txt");
ObjectOutputStream objOut=newObjectOutputStream(fileOut);
ObjectInputStream指向一个输入流对象,准备从文件中读取数据时,先用InputStream的子类创建一个输入流,例如:
FileInputStream fileIn=new FileInputStream("tom.txt");
ObjectInputStream objIn=new ObjectInputStream(fileIn);
使用对象流读写对象时候,要保证对象时序列化的。Java提供的绝大多数对象都是序列化的。
9. 序列化与对象克隆
一个类如果实现了Serializable接口,该类创建的对象就是序列化对象。
使用对象流获取一个序列化对象的克隆
当把一个序列化对象(对象A)写入对象输出流时,JVM会实现Serializable接口中的方法,将对象的序列化信息写入目的地。当ObjectInputStream的流从文件读取对象时,会从文件中读取对象的序列化信息,并根据对象的序列化信息创建一个对象B,B就是A的克隆,例如
class Example implements Serializable{ //实现Serializable接口,使Example类序列化
类体
}
public class Main{
public static void main(String[] args) {
Example exp1=new Example;
File file=new Fiel("EXP.txt");
try{
FileOutputStream fileOut=new FileOutputStream(file);
ObjectOutputStream objectOut=new ObjectOutputStream(fileOut);
objectOut.writeObject(exp1); // 将对象序列化信息写入源中
objectOut.close();
FileInputStream fileIn=new FileInputStream(file);
ObjectInputStream objectIn=new ObjectInputStream(fileIn);
Example exp2=(Example)objectIn.readObject(); // 将源中的序列化信息读出,并创建对象exp2,exp2即exp1的克隆
objectIn.close();
}
catch (IOException | ClassNotFoundException e){
System.out.println(e);
}
}
}
上述代码中Example exp2=(Example)objectIn.readObject();
即创建克隆对象的语句,注意格式
10. 文件锁
FileLock类和FileChannel类。
例如用随机流读写文件时使用文件锁:
(1)先试用RandomAccessFile流建立指向稳健的留的对象,读写属性必须是ew:
RandomAccessFile input=new RandomAccessFile("Example.java","rw");
(2)input流调用FileChannel类的方法getChannel()获得一个连接到底层文件的对象(信道):
FileChannel channel=input.getChannel();
(3)信道调用FileLock类的方法tryLock()或lock()获得一个FileLock(文件锁)对象,这一过程称为对文件加锁:
FileLock lock= channel.tryLock();
文件锁对象产生后,文件不能再被操作或进行加锁。除非让FileLock对象调用release()释放文件锁:
lock.release();
11. 使用Scanner类解析文件
1. 使用默认分隔标记解析文件
创建Scanner对象,指向要解析的文件,例如:
File file=new File("hello.java");
Scanner sc=new Scanner(file);
sc将空白作为分隔标记,调用next()方法返回file中的单词。如果file中最后一个单词已经被返回,sc调用hasNext()方法将返回false,否则返回true
sc可以调用nextInt()、nextDouble()等方法将数字型单词转化为int、double等数据返回。注意:如果单词不是数字型单词,调用nextInt()等方法将发生InputMismatchException异常,在处理异常时用next()方法返回非数字型单词。
2.使用正则表达式作为分隔标记解析文件
创建Scanner对象,指向要解析的文件,并使用useDelimiter方法指定正则表达式作为分隔标记,例如:
File file=new File("hello.java");
Scanner sc=new Scanner(file);
sc.useDelimiter(正则表达式);