------- android培训、java培训、期待与您交流! ----------
IO包中的其他类——打印流PrintStream 和PrintWriter
该流不是读写对应的,PrintStream是字节流,PrintWriter 是字符流,不仅有write()方法写入字节流,还有println方法 可以打印各种数据类型,保证数据原样性把数据打印出来,可以直接操作输入流和文件
字节打印流PrintStream:是OutputStream 的子类, 为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。
构造函数
1,
PrintStream(File file)
可以接收File 对象
2,PrintStream(String fileName)
可以接收字符串类型的路径
3,PrintStream(OutputStream out)
可以接收字节输出流
字符输出流PrintWriter:是Wtirer 的子类,向文本输出流打印对象的格式化表示形式。在web开发时很常用,用来将数据一条条的打印到客户端
构造函数
1,PrintWriter(File file)可以接收File 对象
2,
PrintWriter(String fileName) 可以接收字符串类型的路径
3,
PrintWriter(OutputStream out)可以接收字节输出流
4,
PrintWriter(Writer out)可以接收字符输出流
PrintWriter(OutputStream out, boolean autoFlush)
通过现有的 OutputStream 创建新的 PrintWriter。autoFlush为true时println 方法自动刷新,刷新只对流而言
import java.io.*;
class PrintStreamDemo
{
public static void main(String[] args) throws IOException
{
BufferedReader br=
new BufferedReader(new InputStreamReader(System.in));//定义输入流从键盘输入
//将文件封装到流中,true 自动自动刷到控制台
PrintWriter out=new PrintWriter(new FileWriter("printsteam.txt"),true);//PrintWriter 可以传入字符流
// PrintWriter out=new PrintWriter(System.out,true);//PrintWriter可以传入字节流(true 表示自动刷到控制台,与println同用)
String line=null;
while ((line=br.readLine())!=null)
{
if("over".equals(line))
break;
out.println(line.toUpperCase());//自动换行,当autoFlush 为true println 方法自动刷新
}
br.close();//关闭流
out.close();
}
}
IO包中的其他类——合并流
也叫序列流,表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。该流没有对应的输出流SequenceInputStream
构造方法
SequenceInputStream(InputStream s1,InputStream s2)
通过记住这两个参数来初始化新创建的 SequenceInputStream
(将按顺序读取这两个参数,先读取 s1
,然后读取 s2
),以提供从此 SequenceInputStream
读取的字节。
SequenceInputStream(Enumeration<? extendsInputStream> e)
通过记住参数来初始化新创建的 SequenceInputStream
,该参数必须是生成运行时类型为 InputStream
对象的Enumeration
型参数。
代码示例
需求:将三个文件合并成一个文件
1.txt
2.txt
3.txt
用合并流 合并成4.txt
将多个流合并,用SequenceInputStream(Enumeration <? extends InputStream > e)构造方法
import java.io.*;
import java.util.*;
class SequenceInputStreamDemo
{
public static void main(String[] args) throws IOException
{
//集合 中用到Enumeration,创建集合
Vector<FileInputStream> v=new Vector<FileInputStream>();
v.add(new FileInputStream("1.txt"));
v.add(new FileInputStream("2.txt"));
v.add(new FileInputStream("3.txt"));
Enumeration<FileInputStream> en=v.elements();//集合中的所有元素
SequenceInputStream sis=new SequenceInputStream(en);//接收Enumeration 类型
FileOutputStream fos=new FileOutputStream("4.txt");
byte[] buf=new byte[1024];
int len=0;//返回字节的大小,读到流的末尾返回-1
while ((len=sis.read(buf))!=-1)//加上buf!!!!!!!!!将文件读入缓冲区
{
fos.write(buf,0,len);
fos.flush();//字符流刷新 字节流可以不用刷新
}
sis.close();//但是都要关闭
fos.close();
}
}
IO 包中的其他类——操作对象的流
ObjectInputStream 和ObjectOutputStream
ObjectInputStream 和ObjectOutputStream是流直接操作对象的流,流是操作数据的。对象中封装了数据,存储在堆内存中,当程序运行结束时,内存被释放,堆内存中的对象就被回收,那么可以通过流的方式将堆内存中的对象存放在硬盘上,将对象存储在硬盘上叫做对象的持久化或者对象的序列化。
ObjectOutputStream
ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取(重构)对象。通过在流中使用文件可以实现对象的持久存储。ObjectOutputStream 的write方法不仅可以接收字节型数据,还可以接收其他的基本数据类型,
构造函数
ObjectOutputStream(OutputStream out)
创建写入指定 OutputStream 的 ObjectOutputStream。
常用方法
write(int val)
写入一个字节。
writeInt(int val)
写入一个 32 位的 int 值。
writeDouble(double val)
写入一个 64 位的 double 值。
writeObject(Object obj)
将指定的对象写入 ObjectOutputStream。
注意:
1,将对象写入流时,被写入流的对象要实现Serializable 接口,如果不实现该接口,会抛出NotSerilizabeException异常。
Serializable 接口:类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。序列化接口没有方法或字段,仅用于标识可序列化的语义。没有方法的接口叫做标记接口。
2,静态在方法区中,不能被序列化;如果不想对非静态的数据序列化,可加transient 关键字,不能序列化的数据只能在内存中改变值,不能存储在硬盘上
代码示例
要存储的对象要序列化该对象的类必须实现Serializable接口
import java.io.*;
class Person implements Serializable //实现该接口,对象具有序列化功能
{
String name;
int age;
Person(String name,int age)
{
this.name=name;
this.age=age;
}
public String toString()//复写toString方法
{
return name+"::"+age;
}
}
import java.io.*;
class ObjectStreamDemo
{
public static void main(String[] args) throws Exception
{
//writeObj();
readObj();
}
//读出硬盘的对象文件
public static void readObj()throws Exception
{
ObjectInputStream ois=new ObjectInputStream(new FileInputStream("obj.txt")) ;
Object o=ois.readObject(); //会抛出没有找到类异常 因为文件存储中可能没有存储对象,而是存储其他的数据,会报此异常
System.out.println((Person)o);
}
public static void writeObj() throws IOException//将对象写入硬盘
{
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("obj.txt"));//接收FileOutputStream流对象
oos.writeObject(new Person("lisi",38));
oos.close();
}
}
管道流
PipedInputStream 和PipedOutputStream
管道输入流应该连接到管道输出流;管道输入流提供要写入管道输出流的所有数据字节。通常,数据由某个线程从 PipedInputStream
对象读取,并由其他线程将其写入到相应的PipedOutputStream
。不建议对这两个对象尝试使用单个线程,因为这样可能死锁线程。
管道流是一个涉及多线程的IO流对象
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("zhe shi guan dao liu".getBytes());//转成byte型,因为字符流write 方法接收byte 型
out.close();
}
catch (IOException e)
{
throw new RuntimeException("管道流写入失败");
}
}
}
class PipedStream
{
public static void main(String[] args) throws IOException
{
PipedOutputStream pos=new PipedOutputStream();//创建管道输出流
PipedInputStream pis=new PipedInputStream();//创建写入输入流
pis.connect(pos);//将两个输入和输出管道流连接
Read r=new Read(pis);
Write w=new Write(pos);
Thread t1=new Thread(r);//创建线程
Thread t2=new Thread(w);
t1.start();
t2.start();
}
}
RandomAccessFile
RandomAccessFile 随机访问文件,是IO包中的一个特殊的流对象,该类不是IO体系中的子类,因为它继承 了Object但是它是IO包中的成员,因为具备读写功能
RandomAccessFile 类的实例支持对随机访问文件的读取和写入。随机访问文件的行为类似存储在文件系统中的一个大型 byte 数组。存在指向该隐含数组的光标或索引,称为文件指针;输入操作从文件指针开始读取字节,并随着对字节的读取而前移此文件指针。如果随机访问文件以读取/写入模式创建,则输出操作也可用;输出操作从文件指针开始写入字节,并随着对字节的写入而前移此文件指针。写入隐含数组的当前末尾之后的输出操作导致该数组扩展。该文件指针可以通过getFilePointer
方法读取,并通过 seek
方法设置。
构造函数
RandomAccessFile(File file,String mode)
创建从中读取和向其中写入(可选)的随机访问文件流,该文件由 File
参数指定。
通过构造函数可以看出,该类只能操作文件,而且操作文件还有模式
mode 只接受四种值
"r" | 以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException 。 |
"rw" | 打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。 |
"rws" | 打开以便读取和写入,对于 "rw",还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。 |
"rwd" | 打开以便读取和写入,对于 "rw",还要求对文件内容的每个更新都同步写入到底层存储设备。 |
如果模式为rw 操作的文件不存在,会自动创建,如果存在则不会覆盖
常用方法
读取:
readInt()
从此文件读取一个有符号的 32 位整数。
setLength(long newLength)
设置此文件的长度。
代码示例
public static void readFile()throws IOException
{
RandomAccessFile raf=new RandomAccessFile("random.txt","r");//指定模式为只读
//raf.write("haha".getBytes());//在只读模式下不可以写入,会出现IOException :拒绝访问,所以不可以调用write方法
//调整对象中的指针 前后都可以指
//因为名字占“李四”占四个字节,年龄按4个字节写入的,所以一共占用8个字节(0~7角标)
raf.seek(8*4);//从数组第8*4个角标处开始读取,(读取指定位置的数据)
//跳过字节数,只能往后跳
//raf.skipBytes(8);//跳过8位读取
byte[] buf=new byte[4];
raf.read(buf);
String name=new String(buf);
int age=raf.readInt();//直接读取出4个字节
System.out.println(name);
System.out.println(age);
raf.cloes();//记得关闭流
}
写入
writeInt(int v)
按四个字节将 int
写入该文件,先写高字节。
writeByte(int v)
按单字节值将 byte
写入该文件。
public static void writeFile_2() throws IOException
{
RandomAccessFile raf=new RandomAccessFile("random.txt","rw");
raf.write("李四".getBytes());//将字符串类型变为byte型
//raf.write(258);//可以直接传入int型,取后8为二进制数,会丢失精度
raf.writeInt(258);//按4个字节写入 不会丢失精度
raf.seek(8*4);//调整指针,在指定位置上写
raf.write("周七".getBytes());
raf.writeInt(555);按4个字节写入 不会丢失精度
raf.close();//记得关闭流
}