Java IO核心操作(二)
来源:互联网 发布:淘宝推荐进口零食店 编辑:程序博客网 时间:2024/04/30 12:33
File类只是针对文件爱你本身进行操作,而如果想对文件内容进行操作,则可以使用RandomAccessFile类,此类属于随机读取类,可以随机地读取一个文件中指定位置的数据。
RandomAccessFile类的常用操作方法
需要注意的是如果使用rw方式声明RandomAccessFile对象时,要写入的文件不存在,系统将自动进行创建。
使用RandomAccessFile类写入数据
为了保证可以进行随机读取,所有写入的名字都是8个字节,写入的数字是固定的4个字节。
- 写文件
import java.io.File ;import java.io.RandomAccessFile ;public class RandomAccessFileDemo01{ // 所有的异常直接抛出,程序中不再进行处理 public static void main(String args[]) throws Exception{ File f = new File("d:" + File.separator + "test.txt") ; // 指定要操作的文件 RandomAccessFile rdf = null ; // 声明RandomAccessFile类的对象 rdf = new RandomAccessFile(f,"rw") ;// 读写模式,如果文件不存在,会自动创建 String name = null ; int age = 0 ; name = "zhangsan" ; // 字符串长度为8 age = 30 ; // 数字的长度为4 rdf.writeBytes(name) ; // 将姓名写入文件之中 rdf.writeInt(age) ; // 将年龄写入文件之中 name = "lisi " ; // 字符串长度为8 age = 31 ; // 数字的长度为4 rdf.writeBytes(name) ; // 将姓名写入文件之中 rdf.writeInt(age) ; // 将年龄写入文件之中 name = "wangwu " ; // 字符串长度为8 age = 32 ; // 数字的长度为4 rdf.writeBytes(name) ; // 将姓名写入文件之中 rdf.writeInt(age) ; // 将年龄写入文件之中 rdf.close() ; // 关闭 }};
使用RandomAccessFile类读取数据
读取时直接使用r的模式即可,以只读的方式打开文件。
读取时所有的字符只能按照byte数组的方式读取出来,而且所有的长度是8位。
- 随机读取
import java.io.File ;import java.io.RandomAccessFile ;public class RandomAccessFileDemo02{ // 所有的异常直接抛出,程序中不再进行处理 public static void main(String args[]) throws Exception{ File f = new File("d:" + File.separator + "test.txt") ; // 指定要操作的文件 RandomAccessFile rdf = null ; // 声明RandomAccessFile类的对象 rdf = new RandomAccessFile(f,"r") ;// 以只读的方式打开文件 String name = null ; int age = 0 ; byte b[] = new byte[8] ; // 开辟byte数组 // 读取第二个人的信息,意味着要空出第一个人的信息 rdf.skipBytes(12) ; // 跳过第一个人的信息 for(int i=0;i<b.length;i++){ b[i] = rdf.readByte() ; // 读取一个字节 } name = new String(b) ; // 将读取出来的byte数组变为字符串 age = rdf.readInt() ; // 读取数字 System.out.println("第二个人的信息 --> 姓名:" + name + ";年龄:" + age) ; // 读取第一个人的信息 rdf.seek(0) ; // 指针回到文件的开头 for(int i=0;i<b.length;i++){ b[i] = rdf.readByte() ; // 读取一个字节 } name = new String(b) ; // 将读取出来的byte数组变为字符串 age = rdf.readInt() ; // 读取数字 System.out.println("第一个人的信息 --> 姓名:" + name + ";年龄:" + age) ; rdf.skipBytes(12) ; // 空出第二个人的信息 for(int i=0;i<b.length;i++){ b[i] = rdf.readByte() ; // 读取一个字节 } name = new String(b) ; // 将读取出来的byte数组变为字符串 age = rdf.readInt() ; // 读取数字 System.out.println("第三个人的信息 --> 姓名:" + name + ";年龄:" + age) ; rdf.close() ; // 关闭 }};
程序运行结果:
可以发现,程序中可以随机跳过12位读取信息,也可以回到开始点重新读取。
随机读写流可以实现对文件内容的操作,但是却过于复杂,所以一般情况下操作文件内容往往使用字节流或字符流。
字节流与字符流基本操作
在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据时要使用输入流读取数据,而当程序需要将一些数据保存起来时,就要使用输出流,可以通过下图表示出输入及输出的关系。
在java.io包中流的操作主要有字节流,字符流两大类,两类都有输入和输出操作。在字节流中输出的数据主要使用OutputStream类完成,输入使用InputStream类。在字符流中输出主要是使用Writer类完成,输入主要是使用Reader类完成。
在Java中IO操作也是有相应步骤的,以文件的操作为例,主要的操作流程如下:
- 使用File类打开一个文件。
- 通过字节流或字符流的子类指定输出的位置。
- 进行读/写操作。
- 关闭输入/输出。
下面分别介绍如何使用字节流或字符流保存或读取文件。
字节流
字节流主要操作byte类型数据,以byte数组为准,主要操作类是OutputStream类和InputStream类。
- 字节输出流:OutputStream
OutputStream是整个IO包中字节输出流的最大父类,此类的定义如下:
public abstract class OutputStream extends Object implements Closeable,Flushable
从以上定义中可以发现,OutputStream类是一个抽象类,如果要使用此类,则首先必须通过子类实例化对象。如果现在要操作的是一个文件,则可以使用FileOutputStream类,通过向上转型后,可以为OutputStream实例化,在OutputStream类中的主要操作方法如下表所示
OutputStream类的常用方法
向文件中写入字符串
import java.io.File ;import java.io.OutputStream ;import java.io.FileOutputStream ;public class OutputStreamDemo01{ public static void main(String args[]) throws Exception{ // 异常抛出,不处理 // 第1步、使用File类找到一个文件 File f= new File("d:" + File.separator + "test.txt") ; // 声明File对象 // 第2步、通过子类实例化父类对象 OutputStream out = null ; // 准备好一个输出的对象 out = new FileOutputStream(f) ; // 通过对象多态性,进行实例化 // 第3步、进行写操作 String str = "Hello World!!!" ; // 准备一个字符串 byte b[] = str.getBytes() ; // 只能输出byte数组,所以将字符串变为byte数组 out.write(b) ; // 将内容输出,保存文件 // 第4步、关闭输出流 out.close() ; // 关闭输出流 }};
字节输入流InputStream
既然程序可以向文件中写入内容,则可以通过InputStream从文件中把内容读取出来。InputStream类的定义如下:
public abstract class InputSream extends Object implements Closeable
与OutputStream类一样,InputStream本身也是一个抽象类,必须依靠其子类,如果现在从文件中读取,子类肯定是FileInputStream。InputStream类中的主要方法如表所示:
从文件中读取内容
开辟指定大小的byte数组
import java.io.File ;import java.io.InputStream ;import java.io.FileInputStream ;public class InputStreamDemo03{ public static void main(String args[]) throws Exception{ // 异常抛出,不处理 // 第1步、使用File类找到一个文件 File f= new File("d:" + File.separator + "test.txt") ; // 声明File对象 // 第2步、通过子类实例化父类对象 InputStream input = null ; // 准备好一个输入的对象 input = new FileInputStream(f) ; // 通过对象多态性,进行实例化 // 第3步、进行读操作 byte b[] = new byte[(int)f.length()] ; // 数组大小由文件决定 int len = input.read(b) ; // 读取内容 // 第4步、关闭输出流 input.close() ; // 关闭输出流\ System.out.println("读入数据的长度:" + len) ; System.out.println("内容为:" + new String(b)) ; // 把byte数组变为字符串输出 }};
在使用FileInputStream读取时如果指定的路径不存在,则程序运行会出现异常
除了以上方式,也可以通过循环从文件中一个个地把内容读取进来,直接使用read()方法即可。
使用read()通过循环读取
import java.io.File ;import java.io.InputStream ;import java.io.FileInputStream ;public class InputStreamDemo04{ public static void main(String args[]) throws Exception{ // 异常抛出,不处理 // 第1步、使用File类找到一个文件 File f= new File("d:" + File.separator + "test.txt") ; // 声明File对象 // 第2步、通过子类实例化父类对象 InputStream input = null ; // 准备好一个输入的对象 input = new FileInputStream(f) ; // 通过对象多态性,进行实例化 // 第3步、进行读操作 byte b[] = new byte[(int)f.length()] ; // 数组大小由文件决定 for(int i=0;i<b.length;i++){ b[i] = (byte)input.read() ; // 读取内容 } // 第4步、关闭输出流 input.close() ; // 关闭输出流\ System.out.println("内容为:" + new String(b)) ; // 把byte数组变为字符串输出 }};
另一种方式的读取
import java.io.File ;import java.io.InputStream ;import java.io.FileInputStream ;public class InputStreamDemo05{ public static void main(String args[]) throws Exception{ // 异常抛出,不处理 // 第1步、使用File类找到一个文件 File f= new File("d:" + File.separator + "test.txt") ; // 声明File对象 // 第2步、通过子类实例化父类对象 InputStream input = null ; // 准备好一个输入的对象 input = new FileInputStream(f) ; // 通过对象多态性,进行实例化 // 第3步、进行读操作 byte b[] = new byte[1024] ; // 数组大小由文件决定 int len = 0 ; int temp = 0 ; // 接收每一个读取进来的数据 while((temp=input.read())!=-1){ // 表示还有内容,文件没有读完 b[len] = (byte)temp ; len++ ; } // 第4步、关闭输出流 input.close() ; // 关闭输出流\ System.out.println("内容为:" + new String(b,0,len)) ; // 把byte数组变为字符串输出 }};
文件读到末尾了,则返回的内容为-1。
以上程序代码中要判断temp接收到的内容是否是-1,正常情况下是不会返回-1的,只有当输入流的内容已经读到底,才会返回这个数字,通过此数字可以判断输入流中是否还有其他内容。
以上几种读取字节流的方式,读者最好都掌握,因为随着开发的需要,都有可能使用。
字符输出流Writer
Write本身是一个字符流,此类的定义如下:
public abstract class Writer extends Object implements Appendable,Closeable,Flushable
此类也是一个抽象类,如果要使用此类,则肯定要使用其子类,此时如果是向文件中写入内容,应该使用FileWriter的子类。Write类的常用方法如表所示:
向文件中写入数据
import java.io.File ;import java.io.Writer ;import java.io.FileWriter ;public class WriterDemo01{ public static void main(String args[]) throws Exception{ // 异常抛出,不处理 // 第1步、使用File类找到一个文件 File f= new File("d:" + File.separator + "test.txt") ; // 声明File对象 // 第2步、通过子类实例化父类对象 Writer out = null ; // 准备好一个输出的对象 out = new FileWriter(f) ; // 通过对象多态性,进行实例化 // 第3步、进行写操作 String str = "Hello World!!!" ; // 准备一个字符串 out.write(str) ; // 将内容输出,保存文件 // 第4步、关闭输出流 out.close() ; // 关闭输出流 }};
整个程序与OutputStream的操作流程并没有什么太大的区别,唯一的好处是,可以直接输出字符串,而不用将字符串变为byte数组之后再输出
字符输入流Reader
Reader是使用字符的方式从文件中取出数据,Reader类的定义如下:
public abstract class Reader extends Object implements Readable,Closeable
Reader本身也是一个抽象类,如果现在要从文件中读取内容,则可以直接使用FileReader子类。Reader类的常用方法如表所示:
从文件中读取内容
import java.io.File ;import java.io.Reader ;import java.io.FileReader ;public class ReaderDemo01{ public static void main(String args[]) throws Exception{ // 异常抛出,不处理 // 第1步、使用File类找到一个文件 File f= new File("d:" + File.separator + "test.txt") ; // 声明File对象 // 第2步、通过子类实例化父类对象 Reader input = null ; // 准备好一个输入的对象 input = new FileReader(f) ; // 通过对象多态性,进行实例化 // 第3步、进行读操作 char c[] = new char[1024] ; // 所有的内容都读到此数组之中 int len = input.read(c) ; // 读取内容 // 第4步、关闭输出流 input.close() ; // 关闭输出流 System.out.println("内容为:" + new String(c,0,len)) ; // 把字符数组变为字符串输出 }};
使用循环的方式读取内容
import java.io.File ;import java.io.Reader ;import java.io.FileReader ;public class ReaderDemo02{ public static void main(String args[]) throws Exception{ // 异常抛出,不处理 // 第1步、使用File类找到一个文件 File f= new File("d:" + File.separator + "test.txt") ; // 声明File对象 // 第2步、通过子类实例化父类对象 Reader input = null ; // 准备好一个输入的对象 input = new FileReader(f) ; // 通过对象多态性,进行实例化 // 第3步、进行读操作 char c[] = new char[1024] ; // 所有的内容都读到此数组之中 int temp = 0 ; // 接收每一个内容 int len = 0 ; // 读取内容 while((temp=input.read())!=-1){ // 如果不是-1就表示还有内容,可以继续读取 c[len] = (char)temp ; len++ ; } // 第4步、关闭输出流 input.close() ; // 关闭输出流 System.out.println("内容为:" + new String(c,0,len)) ; // 把字符数组变为字符串输出 }};
字节流与字符流的区别
字节流和字符流的使用非常相似,两者除了操作代码上的不同之外,是否还有其他的不同呢?
实际上字节流在操作本身不会用到缓存区(内存),是文件本身直接操作的,而字符流在操作时使用了缓冲区,通过缓冲区再操作文件,如图所示:
下面以两个写文件的操作为主进行比较,但是在操作时字节流和字符流的操作完成之后都不关闭输出流。
使用字节流不关闭执行
import java.io.File ;import java.io.OutputStream ;import java.io.FileOutputStream ;public class OutputStreamDemo05{ public static void main(String args[]) throws Exception{ // 异常抛出,不处理 // 第1步、使用File类找到一个文件 File f= new File("d:" + File.separator + "test.txt") ; // 声明File对象 // 第2步、通过子类实例化父类对象 OutputStream out = null ; // 准备好一个输出的对象 out = new FileOutputStream(f) ; // 实例化 // 第3步、进行写操作 String str = "Hello World!!!" ; // 准备一个字符串 byte b[] = str.getBytes() ; // 只能输出byte数组,所以将字符串变为byte数组 out.write(b) ; // 写入数据 // 第4步、关闭输出流 // out.close() ; // 关闭输出流 }};
程序运行结果:
Hello Word!!!
此时没有关闭字节流操作,但是文件中也依然存在了输出的内容,证明字节流是直接操作文件本身的。而下面继续使用字符流完成,再观察效果。
使用字符流不关闭执行
import java.io.File ;import java.io.Writer ;import java.io.FileWriter ;public class WriterDemo03{ public static void main(String args[]) throws Exception{ // 异常抛出,不处理 // 第1步、使用File类找到一个文件 File f= new File("d:" + File.separator + "test.txt") ; // 声明File对象 // 第2步、通过子类实例化父类对象 Writer out = null ; // 准备好一个输出的对象 out = new FileWriter(f) ; // 通过对象多态性,进行实例化 // 第3步、进行写操作 String str = "Hello World!!!" ; // 准备一个字符串 out.write(str) ; // 将内容输出,保存文件 // 第4步、关闭输出流 // out.close() ; // 此时,没有关闭 }};
程序运行结果
程序运行后会发现文件中没有任何内容,这是因为字符流操作时使用了缓存区,而在关闭字符流时会强制性地将缓存区中的内容进行输出,但是如果程序没有关闭,则缓冲区中的内容是无法输出的,所以得出结论:字符流使用了缓冲区,而字节流没有使用缓冲区。
提问:什么叫缓冲区?
回答:缓冲区可以简单地理解为一段内存区域,在字符流的操作中,所有的字符都是在内存中形成的,在输出前会将所有的内容暂时保存在内存之中,所以使用了缓冲区暂存数据。
强制性清空缓冲区
import java.io.File ;import java.io.Writer ;import java.io.FileWriter ;public class WriterDemo04{ public static void main(String args[]) throws Exception{ // 异常抛出,不处理 // 第1步、使用File类找到一个文件 File f= new File("d:" + File.separator + "test.txt") ; // 声明File对象 // 第2步、通过子类实例化父类对象 Writer out = null ; // 准备好一个输出的对象 out = new FileWriter(f) ; // 通过对象多态性,进行实例化 // 第3步、进行写操作 String str = "Hello World!!!" ; // 准备一个字符串 out.write(str) ; // 将内容输出,保存文件 // 第4步、关闭输出流 out.flush() ; // 强制性清空缓冲区中的内容 // out.close() ; // 此时,没有关闭 }};
提问:使用字节流好还是字符流好?
回答:使用字节流更好,所有的文件在硬盘或在传输时都是以字节的方式进行的,包括图片等都是按字节的方式存储的,而字符是只有在内存中才会形成,所以在开发中,字节流使用较为广泛。
- Java IO核心操作(二)
- Java IO核心操作(四)
- Java IO核心操作(一)
- Java IO核心操作(三)
- Java IO 核心操作(五)
- Java核心库——IO(二)
- JAVA基础------IO操作(二)
- java中的IO操作总结(二)
- Java中的IO操作总结(二)
- java中的IO操作总结(二)
- Java知识--IO流操作(二)
- Java IO实战操作(二)
- JAVA的IO操作(二)
- JAVA学习——IO操作(二)
- java IO操作(二)---字符流的缓冲区
- java中的IO操作(二)【个人笔记】
- Java IO(二)
- Java--IO(二)
- Image-to-Image Translation with Conditional Adversarial Networks笔记
- 欢迎使用CSDN-markdown编辑器
- bat命令学习笔记(一)
- The 10 Best Foods High in Vitamin C + Health Benefits
- ResourceBundle中文乱码
- Java IO核心操作(二)
- POJ 2114 Boatherds
- FreeBSD搭建Nginx+Apache24+php56+mysql56手把手一步步的笔记
- 算法题笔记
- effective java(7) 之避免使用终结方法
- django xadmin 安装和使用
- caffe2 Windows安装和编译
- 【R笔记】R机器学习(一)——一元回归模型
- size和sizeof的区别