一般来说,流有两种基本形式:输入流和输出流。
根据输入流,程序可以从数据文件读取数据,但不可向输入流中写入数据;反之,通过输出流,程序可以向数据文件中写入数据。
I/O操作的一般步骤
- 构造一个与介质相关的I/O对象 ,已提供一种低层次的方法将数据输入或输出到相应的介质;
- 将与介质相关的对象强制类型转换为他的父类(即抽象I/O类),并利用该对象构造一个流对象。这样便建立起了流类对象与介质相关对象的关联;
- 这时就可以利用流对象的I/O方法进行相应介质上的数据读写。
字节流和字符流
从流中传输的数据单位分为两类:
字节流
从InputStream和OutputStream派生出来的一系列类,以字节(byte)为基本处理单位。字符流
从Reader和Writer派生出来的一系列类,以16位的Unicode码表示的字符为基本处理单元。文件与目录的描述类——File
File类并不用来进行文件的读/写操作,它用来描述文件对象的属性,既可以表示文件,也可以表示目录。使用它提供的方法,我们可以得到所指对象的描述信息,包括名称、存在否、读/写权限、路径等等。
在我们写路径的时候需要注意的问题
当我们在Windows环境使用路径时,其分隔符不能是单一的“\”符号,因为与C/C++相同,符号“\”已经被转意了。例如:
路径是非法的,系统c:\jbuilder3\java\bin
不会识别,正确的应该为
c:\jbilder3\java\bin
或者直接使用反斜杠/来作为路径分隔符。如c:/jbilder3/java/bin
文件夹处理
list方法用于列出一个目录中所有的文件或与某个模式相匹配的文件。
列出目录中与某种模式相匹配的文件:
public String[] list(FilenameFilter filter);
在接口 FilenameFilter中定义的方法只有:
boolean accept(File dir,String name);
利用流进行文件I/O处理
Byte流(字节流)文件的读取
我们主要用其中的FileOutputStream和FileInputStream类,它们的父类为InputStream和OutputStream。Character流(字符流)文件的读取
输入/输出类的父类为Reader、Writer。二进制数据流的文件读取、
如果要读取与机器无关的基本数据类型的数据,如整型或浮点型的二进制数,就要用到二进制数据文件流DataInputStream、DataOutputStream。实际使用中,类DataInputStream和DataOutputStream必须和一个输入类(InputStream)或输出类(OutputStream)联接起来,不能直接用文件名或文件对象(File)对其直接初始化。
随机访问文件的读取
对于InputStream/OutputStream、Reader/Writer类来说,它们都是顺序访问流,只能进行顺序读写。而所谓随机读写,是指读写完上一个字节后,不只能读写其后继的字节,还可以读写文件中任意的字节,就好象文件中有一个随意移动的指针一样。
Java语言提供了类RandomAccessFile来进行随机文件的读取。在生成一个RandomAccessFile对象时,不仅要说明文件对象或文件名,同时还需指明访问模式,即“只读方式”(r)或“读写方式”(rw),这类似于C/C++中的fopen() 函数。
通过类BufferedReader对文件实现按行读取,达到一行一行输出的目的。(字符流)
读取文件信息,保存到控制台。
import java.io.*;
public class ByteInputOutStream {
public static void main(String[] args) throws IOException {
FileReader fr=new FileReader("d:/Java/test.txt");//新建一个要读的文件对象
BufferedReader br=new BufferedReader(fr);//创建一个BufferedReader对象
String line=br.readLine();//用此方法,实现对文件中的内容一行一行读取
while(line!=null){
System.out.println(line);
line=br.readLine();//指针指向下一个位置,如果有的话,不为空;没有的话,为空。
}
br.close();
}
}
结果为:
在控制台输入字符串,然后将其保存到磁盘中
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Scanner;
public class ByteInputOutStream {
public static void main(String[] args) throws IOException {
Scanner sc =new Scanner(System.in);
String str=sc.nextLine();
TextToFile("D://Java/test5", str);
}
/**
* 传入文件名以及字符串, 将字符串信息保存到文件中
*
* @param strFilename
* @param strBuffer
*/
public static void TextToFile(final String strFilename, final String strBuffer)
{
try
{
// 创建文件对象
File fileText = new File(strFilename);
// 向文件写入对象写入信息
FileWriter fileWriter = new FileWriter(fileText);
// 写文件
fileWriter.write(strBuffer);
// 关闭
fileWriter.close();
System.out.println("执行成功");
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
结果为:
此时,可以查看D://Java/test5中的信息,就是控制台输入的字符串。
文件的复制:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
File file = new File("D://Java/ChartRoom.rar");
File fileCopy = new File("D://Java/ChartRoom-copy.rar");
if(!fileCopy.exists())
fileCopy.createNewFile();
try(FileInputStream fileInputStream = new FileInputStream(file); FileOutputStream fileOutputStream = new FileOutputStream(fileCopy)){
/*BufferedInputStream in = new BufferedInputStream(fileInputStream);//这个缓存区可以不定义
BufferedOutputStream out = new BufferedOutputStream(fileOutputStream);*/
byte[] b=new byte[1024];//如果不定义这个变量,直接调用无参的read()方法,将会读取的非常慢,因为他是一个一个比特位读的,而定义了此变量后,他每次是以1024个比特位读的,比较快。
int read=0;
while((read=fileInputStream.read(b))!=-1){
每次都读取b中的内容,如果b中有内容,则输出,反之则为-1
fileOutputStream.write(b);//如果将b改为read,则只能复制1KB
}
fileOutputStream.flush();
System.out.println("复制成功");
}catch(Exception e){
}
}
}
结果为:
复制成功
序列化和反序列化
Java序列化是指把Java对象转换为字节序列的过程;而Java反序列化是指把字节序列恢复为Java对象的过程。
2.为什么需要序列化与反序列化
我们知道,当两个进程进行远程通信时,可以相互发送各种类型的数据,包括文本、图片、音频、视频等, 而这些数据都会以二进制序列的形式在网络上传送。那么当两个Java进程进行通信时,能否实现进程间的对象传送呢?答案是可以的。如何做到呢?这就需要Java序列化与反序列化了。换句话说,一方面,发送方需要把这个Java对象转换为字节序列,然后在网络上传送;另一方面,接收方需要从字节序列中恢复出Java对象。
当我们明晰了为什么需要Java序列化和反序列化后,我们很自然地会想Java序列化的好处。其好处一是实现了数据的持久化,通过序列化可以把数据永久地保存到硬盘上(通常存放在文件里),二是,利用序列化实现远程通信,即在网络上传送对象的字节序列。