Java 输入输出流(上)
目录
Java输入输出流这一章主要介绍Java输入输出流、Java File类、Java File类目录、Java File类文件、Java文件字节输入流、Java文件字节输出流、Java文件字符输入输出流、Java缓冲流、Java随机流、Java数组流、Java数据流、Java对象流、Java序列化与对象克隆、Java使用Scanner解析文件、Java文件对话框、Java带进度条的输入流以及Java文件锁。这一章,我们要学习Java语言的输入输出流,我们都知道,程序在运行期间,可能需要从外部的存储媒介或其他程序中读入所需要的数据,这就需要使用输入流。输入流的指向称为它的源,程序通过输入流读取源中的数据。
1.Java 输入输出流
这一章,我们要学习Java语言的输入输出流,我们都知道,程序在运行期间,可能需要从外部的存储媒介或其他程序中读入所需要的数据,这就需要使用输入流。输入流的指向称为它的源,程序通过输入流读取源中的数据。
另一方面,程序在处理数据后,可能需要将处理的结果写入到永久的存储媒介中或传送给其他的应用程序,这就需要使用输出流。输出流的指向称为它的目的地,程序通过输出流把数据传送到目的地。
虽然I/O流经常与磁盘文件存取有关,但是源和目的地也可以是键盘、内存或显示器窗口。
java.io包(I/O流库)提供大量的流类,所有输入流都是抽象类InputStream(字节输入流)或抽象类Reader(字符输入流)的子类,而所有输出流都是抽象类OutputStream(字节输出流)或抽象类Writer(字符输出流)的子类。
2.Java File类
程序可能经常需要获取磁盘上文件的有关信息或在磁盘上创建新的文件等,这就需要学习使用File类。需要注意的是,File类的对象主要用来获取文件本身的一些信息,例如:文件所在的目录、文件的长度或文件读写权限等,不涉及对文件的读写操作。
创建一个File对象的构造方法有三个:
1)File(String filename);
2)File(String directoryPath,String filename);
3)File(File dir,String filename);
其中,filename是文件名字,directoryPath是文件的路径,dir为一个目录。使用File(String filename)创建文件时,该文件被认为与当前应用程序在同一目录中。
常用的File类的方法如下:
1)public String getName()
获取文件的名字。
2)public boolean canRead()
判断文件是否是可读的。
3)public boolean canWrite()
判断文件是否可被写入。
4)public boolean exists()
判断文件是否存在。
5)public long length()
获取文件的长度(单位是字节)。
6)public String getAbsolutePath()
获取文件的绝对路径。
7)public String getParent()
获取文件的父目录。
8)public boolean isFile()
判断文件是否是一个普通文件,而不是目录。
9)public boolean isDirectory()
判断文件是否是一个目录。
10)public boolean isHidden()
判断文件是否是隐藏文件。
11)public long lastModified()
获取文件最后修改的时间(时间是从1970年午夜至文件最后修改时刻的毫秒数)。
例如,创建一个名字为new.txt的新文件:
import java.io.*;
public class Main {
public static void main(String args[]) {
File f = new File("C:\\ch10","Main.java");
System.out.println(f.getName()+"是可读的吗: "+f.canRead());
System.out.println(f.getName()+"的绝对路径:"+f.getAbsolutePath());
File file = new File("new.txt");
System.out.println("在当前目录下创建新文件"+file.getName());
if(!file.exists()) {
try {
file.createNewFile();
System.out.println("创建成功");
}
catch(IOException exp) {}
}
}
}
运行结果如下:
C:\ch10>java.Main
Main.java是可读的吗:true
Main.java的绝度路径:C:\ch10\Main.java
在当前目录下创建新文件new.txt
创建成功
3.Java File类目录
1.创建目录
File对象调用方法public boolean mkdir()创建一个目录,如果创建成功返回true,否则返回false,如果该目录已经存在将返回false。
2.列出目录中的文件
如果File对象是一个目录,那么该对象调用下述方法列出该目录下的文件和子目录。
1)public String[] list()
用字符串形式返回目录下的全部文件。
2)public File [] listFiles()
用File对象形式返回目录下的全部文件。
有时需要列出目录下指定类型的文件,比如.java、.txt等扩展名的文件。我们可以使用File类的下述两个方法,列出指定类型的文件。
1)public String[] list(FilenameFilter obj)
该方法用字符串形式返回目录下的指定类型的所有文件。
2)public File [] listFiles(FilenameFilter obj)
该方法用File对象形式返回目录下的指定类型的所有文件。
上述两个方法的参数FilenameFilter是一个接口,该接口有一个方法:
public boolean accept(File dir,String name);
File对象dirFile调用list方法时,需向该方法传递一个实现FilenameFilter接口的对象,list方法执行时,参数obj不断回调接口方法accept(File dir,String name),该方法中的参数dir为调用list的当前目录dirFile,参数name被实例化为dirFile目录中的一个文件名,当接口方法返回true时,list方法就将名字为name的文件存放到返回的数组中。
例如,列出当前目录(应用程序所在的目录)下全部.java文件的名字:
import java.io.*;
public class Main {
public static void main(String args[]) {
File dirFile = new File(".");
FileAccept fileAccept = new FileAccept();
fileAccept.setExtendName("java");
String fileName[] = dirFile.list(fileAccept);
for(String name:fileName) {
System.out.println(name);
}
}
}
4.Java File类文件
1.文件的创建与删除
当使用File类创建一个文件对象后,例如:
File file = new File("C:\\myletter","letter.txt");
如果C:\myletter目录中没有名字为letter.txt文件,文件对象file调用方法:
public boolean createNewFile();
可以在C:\myletter目录中建立一个名字为letter.txt的文件。文件对象调用方法public boolean delete()可以删除当前文件,例如:
file.delete();
2.运行可执行文件
当要执行一个本地机器上的可执行文件时,可以使用java.lang包中的Runtime类。首先使用Runtime类声明一个对象:
Runtime ec;
然后使用该类的getRuntime()静态方法创建这个对象:
ec = Runtime.getRuntime();
ec可以调用exec(String command)方法打开本地机器上的可执行文件或执行一个操作。
例如,Runtime对象打开Windows平台上的记事本程序和浏览器:
import java.io.*;
public class Main {
public static void main(String args[]) {
try {
Runtime ce = Runtime.getRuntime();
File file = new File("c:/windows","Notepad.exe");
ce.exec(file.getAbsolutePath());
file = new File("C:\\Program Files\\Internet Explorer","IEXPLORE www.sohu.com");
ce.exec(file.getAbsolutePath());
}
catch(Exception e) {
System.out.println(e);
}
}
}
5.Java 文件字节输入流(1)
使用输入流通常包括4个基本步骤:
(1) 设定输入流的源
(2) 创建指向源的输入流
(3) 让输入流读取源中的数据
(4) 关闭输入流
那么我们这一节通过学习文件字节输入流熟悉一下上述4个基本步骤。
如果对文件读取需求比较简单,那么可以使用FileInputStream类(文件字节输入流),该类是InputStream类的子类(以字节为单位读取文件),该类的实例方法都是从InputStream类继承来的。
我们可以使用FileInputStream类的下列构造方法创建指向文件的输入流。
FileInputStream(String name);
FileInputStream(File file);
第一个构造方法使用给定的文件名name创建FileInputStream流;第二个构造方法使用File对象创建FileInputStream流。参数name和file指定的文件称为输入流的源。
FileInputStream输入流打开一个到达文件的通道(源就是这个文件,输入流指向这个文件)。当创建输入流时,可能会出现错误(也被称为异常)。例如,输入流指向的文件可能不存在。
当出现I/O错误,Java生成一个出错信号,它使用IOException(IO异常)对象来表示这个出错信号。程序必须在try-catch语句中的try块部分创建输入流,在catch块部分检测并处理这个异常。例如,为了读取一个名为hello.txt的文件,建立一个文件输入流in。
try {
FileInputStream in = new FileInputStream("hello.txt"); //创建指向文件hello.txt的输入流
}
catch(IOException e) {
System.out.println("File read error:"+e);
}
或
File f = new File("hello.txt"); //指定输入流的源
try {
FileInputStream in = new FileInputstream(f); //创建指向源的输入流
}
catch(IOException e) {
System.out.println("File read error:"+e);
}
6.Java 文件字节输入流(2)
上一节,我们学习了文件字节输入流的构造方法,这一节,我们继续学习如何使用输入流读取字节以及关闭流。
1.使用输入流读取字节
输入流的目的是提供读取源中数据的通道,程序可以通过这个通道读取源中的数据,文件字节流可以调用从父类继承的read方法顺序地读取文件,只要不关闭流,每次调用read方法就顺序地读取文件中的其余内容,直到文件的末尾或文件字节输入流被关闭。
字节输入流的read方法以字节为单位读取源中的数据。
1)int read()
输入流调用该方法从源中读取单个字节的数据,该方法返回字节值(0~255之间的一个整数),如果未读出字节就返回-1。
2)int read(byte b[])
输入流调用该方法从源中试图读取b.length个字节到字节数组b中,返回实际读取的字节数目。如果到达文件的末尾,则返回-1。
3)int read(byte b[],int off,int len)
输入流调用该方法从源中试图读取len个字节到字节数组b中,并返回实际读取的字节数目。如果到达文件的末尾,则返回-1,参数off指定从字节数组的某个位置开始存放读取的数据。
注意:FileInputStream流顺序地读取文件,只要不关闭流,每次调用read方法就顺序地读取源中其余的内容,直到源的末尾或流被关闭。
2.关闭流
输入流都提供了关闭方法close(),尽管程序结束时会自动关闭所有打开的流,但是当程序使用完流后,显示地关闭任何打开的流仍是一个良好的习惯。如果没有关闭那些被打开的流,那么就可能不允许另一个程序操作这些流所用的资源。
例如:
import java.io.*;
public class Main {
public static void main(String args[]) {
int n = -1;
byte [] a = new byte[100];
try {
File f = new File("Main.java");
InputStream in = new FileInputStream(f);
while((n = in.read(a,0,100)) !=-1) {
String s = new String (a,0,n);
System.out.print(s);
}
in.close();
}
catch(IOException e) {
System.out.println("File read Error"+e);
}
}
}
注意:当把读入的字节转化为字符串时,要把实际读入的字节转化为字符串,例如上述例子中:
String s = new String (a,0,n);
不可写成:
String s = new String (a,0,100);
7.Java 文件字节输出流(1)
前几节我们学习了文件字节输入流,那么既然有文件字节输入流,自然也有相对应的文件字节输出流,这一节我们就来学习文件字节输出流。
使用输出流通常包括4个基本步骤:
(1) 给出输出流的目的地
(2) 创建指向目的地的输出流
(3) 让输出流把数据写入到目的地
(4) 关闭输出流
本节通过学习文件字节输出流熟悉上述4个基本步骤。
如果对文件写入需求比较简单,那么可以使用FileOutputStream类(文件字节输出流),它是OutputStream类的子类(以字节为单位向文件写入内容),该类的实例方法都是从OutputStream类继承来的。
我们可以使用FileOutputStream类的下列具有刷新功能的构造方法创建指向文件的输出流。
FileOutputStream(String name);
FileOutputStream(File file);
第一个构造方法使用给定的文件名name创建FileOutputStream流;第二个构造方法使用File对象创建FileOutputStream流。参数name和file指定的文件称为输出流的目的地。
FileOutputStream输出流开通一个到达文件的通道(目的地就是这个文件,输出流指向这个文件)。
注意:如果输出流指向的文件不存在,Java就会创建该文件,如果指向的文件是已存在的文件,输出流将刷新该文件(使得文件的长度为0)。
除此之外,与创建输入流相同的是,创建输出流时,可能会出现错误(被称为异常),例如,输出流试图要写入的文件可能不允许操作或有其他受限等原因。所以必须在try-catch语句中的try块部分创建输出流,在catch块部分检测并处理这个异常。
例如,创建指向名为destin.txt的输出流out:
try {
FileOutputStream out = new FileoutputStream("destin.txt"); //创建指向文件destin.txt的输出流
}
catch(IOException e) {
System.out.println("File write error:"+e);
}
或
File f = new File("destin.txt"); //指定输出流的目的地
try {
FileOutputStream out = new FileOutputStream(f); //创建指向目的地的输出流
}
catch(IOException e) {
System.out.println("Filewrite:"+e);
}
我们可以使用FileOutputStream类的下列能选择是否具有刷新功能的构造方法创建指向文件的输出流。
FileOutputStream(String name,boolean append);
FileOutputStream(File file,boolean append);
当用构造方法创建指向一个文件的输出流时,如果参数append取值true,输出流不会刷新所指向的文件(假如文件已存在),输出流的write的方法将从文件的末尾开始向文件写入数据,参数append取值false,输出流将刷新所指向的文件(假如文件已经存在)。
8.Java 文件字节输出流(2)
上一节,我们学习了文件字节输出流的构造方法,这一节,我们继续学习如何使用输出流写字节以及关闭流。
1.使用输出流写字节
输出流的目的是提供通往目的地的通道,程序可以通过这个通道将程序中的数据写入到目的地,文件字节流可以调用从父类继承的write方法顺序地写文件。FileOutStream流顺序地向文件写入内容,即只要不关闭流,每次调用write方法就顺序地向文件写入内容,直到流被关闭。
字节输出流的write方法以字节为单位向目的地写数据。
1)void write(int n)
输出流调用该方法向目的地写入单个字节。
2)void write(byte b[])
输出流调用该方法向目的地写入一个字节数组。
3)void write(byte b[],int off,int len)
给定字节数组中起始于偏移量off处取len个字节写到目的地。
4)void close()
关闭输出流。
注意:FileOutputStream流顺序地写文件,只要不关闭流,每次调用write方法就顺序地向目的地写入内容,直到流被关闭。
2.关闭流
在操作系统把程序所写到输出流上的那些字节保存到磁盘上之前,有时被存放在内存缓冲区中,通过调用close()方法,可以保证操作系统把流缓冲区的内容写到它的目的地,即关闭输出流可以把该流所用的缓冲区的内容冲洗掉,通常冲洗到磁盘文件上。
例如:
import java.io.*;
public class Main {
public static void main(String args[]) {
byte [] a = "新年快乐".getBytes();
byte [] b = "Happy New Year".getBytes();
File file = new File("a.txt"); //输出的目的地
try {
OutputStream out = new FileOutputStream(file); //指向目的地的输出流
System.out.println(file.getName()+"的大小:"+file.length()+"字节");
out.write(a); //向目的地写数据
out.close();
out = new FileOutputStream(file,true); //准备向文件尾加内容
System.out.println(file.getName()+"的大小:"+file.length()+"字节");
out.write(b,0,b.length);
System.out.println(file.getName()+"的大小:"+file.length()+"字节");
out.close();
}
catch(IOException e) {
System.out.println("Error"+e);
}
}
}
运行结果如下:
a.txt的大小:0字节
a.txt的大小:12字节
a.txt的大小:26字节
9.Java 文件字符输入输出流
文件字节输入输出流的read和write方法使用字节数组读写数据,即以字节为单位处理数据。因此,字节流不能很好地操作Unicode字符。比如,一个汉字在文件中占用2个字节,如果使用字节流,读取不当会出现“乱码”现象。
与FileInputStream、FileOutputStream字节流相对应的是FileReader、FileWriter字符流(文件字符输入、输出流),FileReader和FileWriter分别是Reader和Writer的子类,其构造方法分别是:
FileReader(String filename);FileReader(File filename);
Fi1eWriter(String filename);FileWriter(File filename);
FileWriter(String filename,boolean append);FileWriter(File filename,boolean append);
字符输入流和输出流的read和write方法使用字符数组读写数据,即以字符为基本单位处理数据。
例如:
import java.io.*;
public class Main {
public static void main(String args[]) {
File sourceFile = new File("a.txt"); //读取的文件
File targetFile = new File("b.txt"); //写入的文件
char c[] = new char[19]; //char型数组
try {
Writer out = new FileWriter(targetFile,true); //指向目的地的输出流
Reader in = new FileReader(sourceFile); //指向源的输入流
int n = -1;
while((n = in.read(c)) !=-1) {
out.write(c,0,n);
}
out.flush();
out.close();
}
catch(IOException e) {
System.out.println("Error"+e);
}
}
}
注意:对于Writer流,write方法将数据首先写入到缓冲区,每当缓冲区溢出时,缓冲区的内容被自动写入到目的地,如果关闭流,缓冲区的内容会立刻被写入到目的地。流调用flush()方法可以立刻冲洗当前缓冲区,即将当前缓冲区的内容写入到目的地。
10.Java 缓冲流
前几节我们学习了文件字节输入输出流和文件字符输入输出流,这一节我们学习一个新的概念——缓冲流。那什么叫做缓冲流呢?缓冲流又能起到什么作用呢?
在Java中,我们把BufferedReader和BufferedWriter类创建的对象称为缓冲输入输出流,二者增强了读写文件的能力。比如,Sudent.txt是一个学生名单,每个姓名占一行。如果我们想读取名字,那么每次必须读取一行,使用FileReader流很难完成这样的任务,因为,我们不清楚一行有多少个字符,FileReader类没有提供读取一行的方法。
Java提供了更高级的流:BufferedReader流和BufferedWriter流,二者的源和目的地必须是字符输入流和字符输出流。因此,如果把文件字符输入流作为BufferedReader流的源,把文件字符输出流作为BufferedWriter流的目的地,那么,BufferedReader和BufferedWriter类创建的流将比字符输入流和字符输出流有更强的读写能力。比如,BufferedReader流就可以按行读取文件。
BufferedReader类和BufferedWriter的构造方法分别是:
BufferedReader(Reader in);
BufferedWriter(Writer out);
BufferedReader流能够读取文本行,方法是readLine()。通过向BufferedReader传递一个Reader子类的对象,比如FileReader的实例,来创建一个BufferedReader对象,例如:
FileReader inOne = new FileReader("Student.txt");
BufferedReader inTwo = BufferedReader(inOne);
然后inTwo流调用readLine()方法中读取Student.txt,例如:
String strLine = inTwo.readLine();
类似地,可以将BufferedWriter流和FileWriter流连接在一起,然后使用BufferedWriter流将数据写到目的地,例如:
FileWriter tofile = new FileWriter("hello.txt");
BufferedWriter out = BufferedWriter(tofile);
然后out使用BufferedReader类的方法write(String s,int off,int len)把字符串s写到hello.txt中,参数off是s开始处的偏移量,len是写入的字符数量。
另外,BufferedWriter流有一个独特的向文件写入一个回行符的方法:
newLine();
可以把BufferedReader和BufferedWriter称为上层流,把它们指向的字符流称为底层流,Java采用缓存技术将上层流和底层流连接。底层字符输入流首先将数据读入缓存,BufferedReader流再从缓存读取数据;BufferedWriter流将数据写入缓存,底层字符输出流会不断地将缓存中的数据写入到目的地。当BufferedWriter流调用flush()刷新缓存或调用close()方法关闭时,即使缓存没有溢出,底层流也会立刻将缓存的内容写入目的地。
注意:关闭输出流时要首先关闭缓冲输出流,然后关闭缓冲输出流指向的流,即先关闭上层流再关闭底层流。在编写代码时只需关闭上层流,那么上层流的底层流将自动关闭。
例如:
由英语句子构成的文件english.txt如下,每句占一行:
The arrow missed the target.
They rejected the union demand.
Where does this road go to?
要求按行读取english.txt,并在该行的后面加上该英语句子中含有的单词数目,然后再将该行写入到一个名字为englishCount.txt的文件中,代码如下:
import java.io.*;
import java.util.*;
public class Main {
public static void main(String args[]) {
File fRead = new File("english.txt");
File fWrite = new File("englishCount.txt");
try {
Writer out = new FileWriter(fWrite);
BufferedWriter bufferWrite = new BufferedWriter(out);
Reader in = new FileReader(fRead);
BufferedReader bufferRead = new BufferedReader(in);
String str = null;
while((str = bufferRead.readLine()) !=null) {
StringTokenizer fenxi = new StringTokenizer(str);
int count = fenxi.countTokens();
str = str+"句子中单词个数:"+count;
bufferWrite.write(str);
bufferWrite.newLine();
}
bufferWrite.close();
out.close();
in = new FileReader(fWrite);
bufferRead = new BufferedReader(in);
String s = null;
System.out.println(fWrite.getName()+"内容:");
while((s=bufferRead.readLine()) !=null) {
System.out.println(s);
}
bufferRead.close();
in.close();
}
catch(IOException e) {
System.out.println(e.toString());
}
}
}
运行结果如下:
englishCount.txt内容:
The arrow missed the target.句子中单词个数:5
They rejected the union demand.句子中单词个数:5
Where does this road go to?句子中单词个数:6
原文地址:https://blog.csdn.net/xinfanyyds/article/details/145160102
免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!