Java学习(二)读文件
文件类的继承关系如下:
(图片出处:https://blog.csdn.net/zhangbinu/article/details/51362612/)
1.读文件
1.1以字符流方式读文件
字符流:输入和输出操作的是字符
1.1.1InputStreamReader
InputStreamReader继承自抽象类 Reader
public class InputStreamReader extends Reader {}
下面是InputstreamReader的全部公共方法:
//所有的构造方法参数都是InputStream
public InputStreamReader(InputStream in)
public InputStreamReader(InputStream in, String charsetName) //用指定字符集创建对象
public InputStreamReader(InputStream in, Charset cs)
public InputStreamReader(InputStream in, CharsetDecoder dec)
public String getEncoding() //获取字符集
public int read() //读取单个字符的字符集编码,如果流被读完,返回-1
public int read(char cbuf[], int offset, int length) //读取部分字符到字符数组cbuf
public boolean ready() //如果该流的输入缓冲区非空,返回true
public void close()
1.1.2FileReader
FileReader 继承自InputStreamReader ,在类文件中只新增的三个构造方法:
public FileReader(String fileName)
public FileReader(File file)
public FileReader(FileDescriptor fd)
这里不论我们使用InputStreamReader 还是使用FileReader,本质都是使用InputStreamReader 类下公共方法read(), 和 read(char cbuf[], int offset, int length)
注:
1、FileReader类仅仅是InputStreamReader的简单衍生并未扩展任何功能
2、FileReader类读取数据实质是InputStreamReader类在读取,而InputStreamReader读取数据实际是StreamDecoder类读取
这两个类的使用是类似的:
1.1.2.1read()方法
read()方法:从输入流中读取数据的下一个字节。返回 0 到 255 范围内的 int 字节值。如果因为已经到达流末尾而没有可用的字节,则返回值 -1。在输入数据可用、检测到流末尾或者抛出异常前,此方法一直阻塞。
子类必须提供此方法的一个实现。
package fileee;
import java.io.*;
public class fileee {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("src/FileWrite_test.txt");
int ch;
//这样写可以防止最后取值到-1的情况
while((ch=fr.read())!=-1){
System.out.print((char) ch+"ss"); //char就可以把原本是数字的文件翻译回来
}
fr.close();
}
}
1.1.2.2read(char cbuf[], int offset, int length)
read(char cbuf[], int offset, int length)方法:将输入流中最多 len 个数据字节读入 byte 数组。尝试读取 len 个字节,但读取的字节也可能小于该值。以整数形式返回实际读取的字节数。
在输入数据可用、检测到流末尾或者抛出异常前,此方法一直阻塞。
如果 len 为 0,则不读取任何字节并返回 0;否则,尝试读取至少一个字节。如果因为流位于文件末尾而没有可用的字节,则返回值 -1;否则,至少读取一个字节并将其存储在 b 中。
将读取的第一个字节存储在元素 b[offset] 中,下一个存储在 b[offset+1] 中,依次类推。读取的字节数最多等于 len。设 k 为实际读取的字节数;这些字节将存储在 b[offset] 到 b[offset+k-1] 的元素中,不影响b[offset+k] 到 b[offset+len-1] 的元素。
在任何情况下,b[0] 到 b[offset] 的元素以及 b[offset+len] 到 b[b.length-1] 的元素都不会受到影响。
类 InputStream 的 read(b, offset, len) 方法重复调用方法 read()。如果第一次这样的调用导致IOException,则从对 read(b, off, len) 方法的调用中返回该异常。如果对 read() 的任何后续调用导致 IOException,则捕获该异常并将其视为到达文件末尾;到达该点时读取的字节存储在 b 中,并返回发生异常之前读取的字节数。在已读取输入数据 len 的请求数量、检测到文件结束标记、抛出异常前,此方法的默认实现将一直阻塞。建议子类提供此方法更为有效的实现。
import java.io.*;
public class m{
public static void main(String[] args){
int num=0;
int count=0;
char[] buf=new char[6];
//打开文件
FileReader fr = null;
try {
fr = new FileReader("txt.txt");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//取出字符存到buf数组中
try {
while((num=fr.read(buf))!=-1) {
//String(char[] cbuf,a,b),从cbuf的位置a开始取出连续的b个char组成字符串
System.out.println(new String(buf,0,num)+num);
count++;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//检测一下是否取到相应的数据
for(int i=0;i<6;i++) {
System.out.print(buf[i]+" ");
}
System.out.println("名字:"+count);
}
1.1.3 BufferedReader
BufferedReader的文档(来自jdk1.8)
Reads text from a character-input stream, buffering characters so as to provide for the efficient reading of characters, arrays, and lines. The buffer size may be specified, or the default size may be used. The default is large enough for most purposes.
In general, each read request made of a Reader causes a corresponding read request to be made of the underlying character or byte stream. It is therefore advisable to wrap a BufferedReader around any Reader whose read() operations may be costly, such as FileReaders and InputStreamReaders. For example,
BufferedReader in = new BufferedReader(new FileReader(“foo.in”));
will buffer the input from the specified file. Without buffering, each invocation of read() or readLine() could cause bytes to be read from the file, converted into characters, and then returned, which can be very inefficient.
Programs that use DataInputStreams for textual input can be localized by replacing each DataInputStream with an appropriate BufferedReader.
BufferedReader 的全部公有方法:
public BufferedReader(Reader in, int sz)
public BufferedReader(Reader in)
public int read()
public int read(char cbuf[], int off, int len)
public String readLine()
public long skip(long n)
public boolean ready()
public boolean markSupported()
public void mark(int readAheadLimit)
public void reset()
public void close()
public Stream<String> lines()
使用BufferedReader 的例子:
利用BufferedReader中的readLine()方法。BufferedReader.readLine(),没有参数,返回——包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null。
try (FileReader reader = new FileReader("src/P1/txt/" + filename);
BufferedReader br = new BufferedReader(reader);){
String line;
int i, j ,k;
j = 0;
i = 0;
k = 0;
while ((line = br.readLine()) != null) {
j++;
String[] word = line.split("\t");
i = word.length;
if(j==1) {
k= i;
}
if(k!=i) {
flag = 1;
}
}
linenumber = j;
columnnumber = i;
br.close();
}catch(Exception e) {
e.printStackTrace();
}
reader在try里面,执行完可以自动关闭故不需要写reader.close();
1.2以字节流方式读文件
1.2.1FileInputStream
根本还是应用read有参或无参方法
public static void myRead(String string){
File file = new File(string); //1、建立连接
InputStream is = null;
try {
is = new FileInputStream(file); //2、选择流(此处为输入流)
// //和上一句功能一样,BufferedInputStream是增强流,加上之后能提高输入效率,建议!
// is = new BufferedInputStream(new FileInputStream(file));
int len = 0;
byte[] car = new byte[1024];
while((len = is.read(car))!= -1) { //3、操作:以每次car大小读取
String ss = new String(car,0,len); // 将byte类型的数组转化成字符串,方便下面输出
System.out.println(ss);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
System.out.println("文件不存在!");
} catch (IOException e) {
e.printStackTrace();
System.out.println("读取文件失败!");
}finally {
if (is != null) { //若is还存在就需要释放,否则不需要释放
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
System.out.println("关闭文件输入流失败");
}
}
}
}
}
1.2.1BufferedInputStream
BufferedInputStream和BufferedReader类似,使用它们可以防止每次读取数据时进行实际的写操作,代表着使用缓冲区。
我们有必要知道不带缓冲的操作,每读一个字节就要写入一个字节,由于涉及磁盘的IO操作相比内存的操作要慢很多,所以不带缓冲的流效率很低。带缓冲的流,可以一次读很多字节,但不向磁盘中写入,只是先放到内存里。等凑够了缓冲区大小的时候一次性写入磁盘,这种方式可以减少磁盘操作次数,速度就会提高很多!
同时正因为它们实现了缓冲功能,所以要注意在使用BufferedInputStream读完数据后,要调用flush()方法或close()方法,强行将缓冲区中的数据写出。否则可能无法写出数据。
使用BufferedInputStream或BufferedReader实现了缓冲功能的输入流,使效率更高,速度更快。