IO(Input Output)流,用来处理设备之间的数据传输
Java对数据的操作是通过流的方式
Java用于操作流的对象都在IO包中
流按操作数据分为两种:字节流与字符流
流按流向分为:输入流,输出流
最开始只有字节流,这符合计算机底层的存储原理,后来为了文本的操作方便开始引入字符流
字节流的抽象基类:
字符流的抽象基类:
注:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。如:InputStream的子类FileInputStream,Reader的子类FileReader,后缀名是父类名。 前缀名是该流对象的功能
FileWriter构造方法 |
---|
FileWriter(File file) 根据给定的 File 对象构造一个 FileWriter 对象 |
FileWriter**(File file, boolean append) 根据给定的 File 对象构造一个 FileWriter 对象 |
FileWriter(FileDescriptor fd) 构造与某个文件描述符相关联的 FileWriter 对象 |
FileWriter(String fileName) 根据给定的文件名构造一个 FileWriter 对象 |
FileWriter(String fileName, boolean append) 根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象 |
FileWriter fw = new FileWriter("Test.txt");
fw.write("text");
fw.close();
FileWriter fw = null;
try{
fw = new FileWriter("Test.txt");
fw.write("text");
} catch (IOException e){
System.out.println(e.toString());
} finally{
If(fw != null)
try{
fw.close();
} catch (IOException e){
System.out.println(e.toString());
}
}
当需要在已有文件追加内容时,使用FileWriter(filename, true)来写入文件
注:
FileReader构造方法 |
---|
FileReader(File file) 在给定从中读取数据的 File 的情况下创建一个新 FileReader |
FileReader(FileDescriptor fd) 在给定从中读取数据的 FileDescriptor 的情况下创建一个新 FileReader |
FileReader(String fileName) 在给定从中读取数据的文件名的情况下创建一个新 FileReader |
read()
方法用于读取一个字符,每次读完会自动后移一位,当文件读取完成,返回-1
read(buf)
方法用于将数组读入数组,返回读到的字符长度,如果一次没读取完,下一次再调用继续读取后面的字符,当返回-1代表文件读取完毕
建立一个流对象,将已存在的一个文件加载进流
FileReader fr = new FileReader(“Test.txt”);
创建一个临时存放数据的数组
char[] ch = new char[1024];
调用流对象的读取方法将流中的数据读入到数组中
fr.read(ch);
FileReader fr = null;
try{
fr = new FileReader("c:\\test.txt");
char[] buf = new char[1024];
int len= 0;
while((len = fr.read(buf)) != -1){
System.out.print(new String(buf,0,len));
}
} catch (IOException e){
System.out.println("read-Exception :" + e.toString());
} finally{
if(fr != null){
try{
fr.close();
} catch (IOException e){
System.out.println("close-Exception :" + e.toString());
}
}
}
import java.io.*;
class Text {
public static void main(String[] args) throws IOException {
MyCopy();
}
public static void MyCopy() {
FileWriter fw = null;
FileReader fr = null;
try {
fw = new FileWriter("Demo_copy.txt");
fr = new FileReader("Demo.java");
char[] buf = new char[1024];
int len = 0;
while((len=fr.read(buf))!=-1) {
fw.write(buf,0,len);
}
} catch (IOException e) {
throw new RuntimeException("读写失败");
} finally {
if(fr != null)
try {
fr.close();
} catch (IOException e) {
}
if(fw != null)
try {
fw.close();
} catch (IOException e) {
}
}
}
}
/
“或者”\\
"具备缓冲区的字符流
flush()
刷新newLine();
getLineNumber()
,还可以设置行号setLineNumber()
import java.io.*;
class Text {
public static void main(String[] args) {
BufferedReader bufr = null;
BufferedWriter bufw = null;
try {
bufr = new BufferedReader(new FileReader("Demo.java"));
bufw = new BufferedWriter(new FileWriter("Demo_copy.txt"));
String line = null;
while((line = bufr.readLine()) != null) {
bufw.write(line);
bufw.newLine();
bufw.flush();
}
} catch (IOException e) {
throw new RuntimeException("读写失败");
} finally {
try {
if(bufr != null)
bufr.close();
} catch (IOException e) {
throw new RuntimeException("读取关闭失败");
}
try {
if(bufw != null)
bufw.close();
} catch (IOException e) {
throw new RuntimeException("写入关闭失败");
}
}
}
}
基本操作与字符流类相同
但它不仅可以操作字符,还可以操作其他媒体文件
而字符流不可以操作媒体文件
e.g.(复制图片)
import java.io.*;
class Test {
public static void main(String[] args) {
FileOutputStream fos = null;
FileInputStream fis = null;
try {
fos = new FileOutputStream("c:\\2.bmp");
fis = new FileInputStream("c:\\1.bmp");
byte[] buf = new byte[1024];
int len = 0;
while((len = fis.read(buf)) != -1) {
fos.write(buf,0,len);
}
} catch (IOException e) {
throw new RuntimeException("复制文件失败");
} finally {
try {
if(fis != null)
fis.close();
} catch (IOException e) {
throw new RuntimeException("读取关闭失败");
}
try {
if(fos!=null)
fos.close();
} catch (IOException e) {
throw new RuntimeException("写入关闭失败");
}
}
}
}
同样是提高了字节流的读写效率
public static void copy()throws IOException {
BufferedInputStream bufis = new BufferedInputStream(new FileInputStream("c:\\0.mp3"));
BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("c:\\1.mp3"));
int by = 0;
while((by = bufis.read()) != -1) {
bufos.write(by);
}
bufos.close();
bufis.close();
}
转换流的应用
System类中的字段:in,out
它们各代表了系统标准的输入和输出设备
默认输入设备是键盘,输出设备是显示器
System.in的类型是InputStream
System.out的类型是PrintStream是OutputStream的子类FilterOutputStream的子类
例:获取键盘录入数据,然后将数据流向显示器,那么显示器就是目的地
System.setIn(new FileInputStream(“1.txt”));
//将源改成文件1.txtSystem.setOut(new FileOutputStream(“2.txt”));
//将目的改成文件2.txtBfferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
import java.io.*;
class Test {
public static void main(String[] args) throws IOException {
//获取键盘录入对象。
//InputStream in = System.in;
//将字节流对象转成字符流对象,使用转换流。InputStreamReader
//InputStreamReader isr = new InputStreamReader(in);
//为了提高效率,将字符串进行缓冲区技术高效操作。使用BufferedReader
//BufferedReader bufr = new BufferedReader(isr);
//键盘的最常见写法。
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
String line = null;
while((line = bufr.readLine()) != null) {
if("over".equals(line))
break;
bufw.write(line);
bufw.newLine();
bufw.flush();
}
bufr.close();
}
}
明确源和目的
源:输入流。InputStream Reader
目的:输出流。OutputStream Writer
操作的数据是否是纯文本
是:字符流
不是:字节流
File(File parent, String child)
File(String pathname)
File(String parent, String child)
File(URI uri)
boolean createNewFile(); //在指定位置创建文件,如果该文件已经存在,则不创建,返回false
boolean mkdir(); //创建文件夹
boolean mkdirs(); //创建多级文件夹
boolean delete(); //删除失败返回false。如果文件正在被使用,则删除不了返回falsel。
void deleteOnExit(); //在程序退出时删除指定文件。
boolean exists(); //文件是否存在
isFile();
isDirectory();
isHidden();
isAbsolute();
getName();
getPath();
getParent();
getAbsolutePath();
long lastModified();
long length();
import java.io.*;
class Test {
public static void main(String[] args) {
File dir = new File("d:\\testdir");
removeDir(dir);
}
public static void removeDir(File dir) {
File[] files = dir.listFiles();
for(int x = 0; x < files.length; x++) {
if(files[x].isDirectory())
removeDir(files[x]);
else
System.out.println(files[x].toString() + ":-file-:" + files[x].delete());
}
System.out.println(dir + "::dir::" + dir.delete());
}
}
该流提供了打印方法,可以将各种数据类型的数据都原样打印
字节打印流:PrintStream
构造函数可以接收的参数类型:
1,file对象。File
2,字符串路径。String
3,字节输出流。OutputStream
字符打印流:PrintWriter
构造函数可以接收的参数类型:
1,file对象。File
2,字符串路径。String
3,字节输出流。OutputStream
4,字符输出流,Writer
import java.io.*;
class Test {
public static void main(String[] args) throws IOException {
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(new FileWriter("a.txt"), true);
String line = null;
while((line = bufr.readLine()) != null) {
if("over".equals(line))
break;
out.println(line);
//out.flush();
}
out.close();
bufr.close();
}
}
将多个流合并成一个流
import java.io.*;
import java.util.*;
class Test {
public static void main(String[] args) throws IOException {
Vector<FileInputStream> v = new Vector<FileInputStream>();
v.add(new FileInputStream("c:\\1.txt"));
v.add(new FileInputStream("c:\\2.txt"));
v.add(new FileInputStream("c:\\3.txt"));
Enumeration<FileInputStream> en = v.elements();
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("c:\\4.txt");
byte[] buf = new byte[1024];
int len = 0;
while((len = sis.read(buf)) != -1) {
fos.write(buf, 0, len);
}
fos.close();
sis.close();
}
}
从文本中加载键值对
BufferedReader bufr = new BufferedReader(new FileReader("info.txt"));
Properties prop = new Properties();
String line = null;
while((line = bufr.readLine()) != null) {
String[] arr = line.split("=");
prop.setProperty(arr[0],arr[1]);
}
bufr.close();
System.out.println(prop);
Properties可以直接从流中获取数据,修改并存储
Properties prop = new Properties();
FileInputStream fis = new FileInputStream("info.txt");
prop.load(fis); //将流中的数据加载进集合
prop.setProperty("testKey","testValue");
FileOutputStream fos = new FileOutputStream("info.txt");
prop.store(fos,"note");
prop.list(System.out);
fos.close();
fis.close();
ObjectInputStream与ObjectOutputStream
被操作的对象需要实现Serializable(标记接口)
静态属不能被序列化
要使改变过后的类还能使用以前的序列化,就需要自定义序列ID
不想序列化的成员加上transient关键字
import java.io.*;
class Person implements Serializable {
public static final long serialVersionUID = 42L;
private String name;
transient int age;
static String country = "cn";
Person(String name, int age, String country) {
this.name = name;
this.age = age;
this.country = country;
}
public String toString() {
return name + ":" + age + ":" + country;
}
}
import java.io.*;
class Test {
public static void main(String[] args) throws Exception {
//writeObj();
readObj();
}
public static void readObj()throws Exception {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.object"));
Person p = (Person)ois.readObject();
System.out.println(p);
ois.close();
}
public static void writeObj()throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.object"));
oos.writeObject(new Person("name",0,"cn"));
oos.close();
}
}
PipedInputStream和PipedOutputStream
输入输出可以直接进行连接,通过结合线程使用
使用单线程时,容易造成死锁
import java.io.*;
class Read implements Runnable {
private PipedInputStream in;
Read(PipedInputStream in) {
this.in = in;
}
public void run() {
try {
byte[] buf = new byte[1024];
int len = in.read(buf);
String s= new String(buf, 0, len);
System.out.println(s);
in.close();
} catch (IOException e) {
throw new RuntimeException("管道读取流失败");
}
}
}
class Write implements Runnable {
private PipedOutputStream out;
Write(PipedOutputStream out) {
this.out = out;
}
public void run() {
try {
out.write("Test Datas".getBytes());
out.close();
} catch (Exception e) {
throw new RuntimeException("管道输出流失败");
}
}
}
class Test {
public static void main(String[] args) throws IOException {
PipedInputStream in = new PipedInputStream();
PipedOutputStream out = new PipedOutputStream();
in.connect(out); //连接管道
Read r = new Read(in);
Write w = new Write(out);
new Thread(r).start();
new Thread(w).start();
}
}
该类不是算是IO体系中子类
而是直接继承自Object
但是它是IO包中成员。因为它具备读和写功能
内部封装了一个数组,而且通过指针对数组的元素进行操作
可以通过getFilePointer获取指针位置,同时可以通过seek改变指针的位置
其实完成读写的原理就是内部封装了字节输入流和输出流
通过构造函数可以看出,该类只能操作文件
而且操作文件还有模式:只读r,读写rw等
如果模式为只读r:不会创建文件,会去读取一个已存在文件,如果该文件不存在,则会出现异常
如果模式rw:操作的文件不存在,会自动创建,如果存在则不会覆盖
构造方法
RandomAccessFile(File file, String mode) | 创建从中读取和向其中写入(可选)的随机访问文件流,该文件由 File 参数指定 |
RandomAccessFile(String name, String mode) | 创建从中读取和向其中写入(可选)的随机访问文件流,该文件具有指定名称 |
值 | 含意 |
"r" | 以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException |
"rw" | 打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件 |
"rws" | 打开以便读取和写入,对于 "rw",还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备 |
"rwd" | 打开以便读取和写入,对于 "rw",还要求对文件内容的每个更新都同步写入到底层存储设备 |
可以用来实现多线程的下载
import java.io.*;
class Test {
public static void main(String[] args) throws IOException {
writeFile();
//readFile();
}
public static void readFile()throws IOException {
RandomAccessFile raf = new RandomAccessFile("ran.txt","r");
//调整对象中指针。
//raf.seek(8*1);
//跳过指定的字节数
raf.skipBytes(8);
byte[] buf = new byte[4];
raf.read(buf);
String name = new String(buf);
int age = raf.readInt();
System.out.println("name=" + name);
System.out.println("age=" + age);
raf.close();
}
//实现在指定位置写入
public static void writeFile_2()throws IOException {
RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
raf.seek(8 * 3);
raf.write("王五".getBytes());
raf.writeInt(21);
raf.close();
}
public static void writeFile()throws IOException {
RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
raf.write("张三".getBytes());
raf.writeInt(20);
raf.write("李四".getBytes());
raf.writeInt(22);
raf.close();
}
}
DataInputStream
与DataOutputStream
import java.io.*;
class Test {
public static void main(String[] args) throws IOException {
//writeData();
//readData();
}
public static void readData() throws IOException {
DataInputStream dis = new DataInputStream(new FileInputStream("data.data"));
int num = dis.readInt();
boolean b = dis.readBoolean();
double d = dis.readDouble();
System.out.println("num = " + num);
System.out.println("b = " + b);
System.out.println("d = " + d);
dis.close();
}
public static void writeData() throws IOException {
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.data"));
dos.writeInt(123);
dos.writeBoolean(true);
dos.writeDouble(876.543);
dos.close();
}
}
ByteArrayInputStream
与ByteArrayOutputStream
ByteArrayInputStream
包含一个内部缓冲区,该缓冲区包含从流中读取的字节。内部计数器跟踪read
方法要提供的下一个字节ByteArrayOutputStream
实现了一个输出流,其中的数据被写入一个byte
数组。缓冲区会随着数据的不断写入而自动增长。可使用toByteArray()
和toString()
获取数据ByteArrayInputStream
与ByteArrayOutputStream
无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何IOException
ByteArrayInputStream:在构造的时候,需要接收数据源,而且数据源是一个字节数组
ByteArrayOutputStream:在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组,
这就是数据目的地。
因为这两个流对象都操作的数组,并没有使用系统资源,所以,不用进行close关闭
import java.io.*;
class Test {
public static void main(String[] args) {
//数据源
ByteArrayInputStream bis = new ByteArrayInputStream("ABCDEF".getBytes());
//数据目的
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int by = 0;
while((by = bis.read()) != -1) {
bos.write(by);
}
System.out.println(bos.size());
System.out.println(bos.toString());
}
}
操作字符数组
CharArrayReader
与CharArrayWrite
与操作字节数组类似
操作字符串
StringReader
与StringWriter
与操作字节数组类似