打印流
可以直接操作输入流和文件
/*
* 打印流:PrintStream
* 特点:
* 1,给字节输出流提供了打印方法。
* 2,方便打印数值表示形式。
* 3,构造函数接收File对象,字符串路径,OutputStream.
*/
PrintStream ps = new PrintStream("temp\\ps2.txt");
// ps.write(97);//write写出一个int,只将最低一个字节写出。
// ps.write(353);
// ps.print(97);
ps.print(353); // 353 --> "353" --> 将数值保持表现形式不变,写到目的地中。都将数据转成字符串。
ps.close();
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter("temp\\pw.txt")),true);
String line = null;
while((line=bufr.readLine())!=null){
if("over".equals(line))
break;
pw.println(line.toUpperCase());
// pw.flush();
}
pw.close();
bufr.close();
序列流
对多个流进行合并。
@Test
public void demo() throws Exception {
/*
* 演示序列流。 SequenceInputStream: 特地: 1,将多个源合并成一个源, 2,接收的是一个枚举接口对象。
*/
/* 效率太低了 不使用
* Vector<FileInputStream> v = new Vector<FileInputStream>(); v.add(new
* FileInputStream("temp\\1.txt")); v.add(new
* FileInputStream("temp\\2.txt")); v.add(new
* FileInputStream("temp\\3.txt"));
*/
ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
for (int x = 1; x <= 3; x++) {
al.add(new FileInputStream("temp\\" + x + ".txt"));
}
Enumeration<FileInputStream> en = Collections.enumeration(al);
SequenceInputStream sis = new SequenceInputStream(en);
BufferedReader in=new BufferedReader(new InputStreamReader(sis));
BufferedWriter out=new BufferedWriter(new FileWriter("temp/jiangyi.txt"));
String line=null;
while((line=in.readLine())!=null){
out.write(line);
out.newLine();
out.flush();
}
out.close();
in.close();
}
/*
* 将一个文件按照指定的大小进行切割。
* 思路:
* 1,一个输入流关联源文件。
* 2,当缓冲的数据满足了指定的大小后,则新建一个目的地进行继续的数据存储。
* 3,给每一个碎片文件编号。
*/public static void splitFile(File srcFile) throws IOException {
FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = null;
byte[] buf = new byte[1024*1024];//创建一个1M的缓冲区。
int len = 0;
int count = 1;
while((len=fis.read(buf))!=-1){
fos = new FileOutputStream(new File("temp\\",(count++)+".part"));
fos.write(buf,0,len);
fos.close();
}
//将源文件的配置信息存储到一个文件中和碎片文件在一起。
Properties prop = new Properties();
prop.setProperty("partcount", count+"");
prop.setProperty("srcfilename", srcFile.getName());
fos = new FileOutputStream(new File("temp\\",count+".properties"));
prop.store(fos, "save partfiles info");
fos.close();
fis.close();
}
操作对象(对象序列化)
被操作的对象需要实现Serializable (标记接口);
public static void writeObj() throws IOException {
/*
* 对象的序列化 ObjectOutputStream
* 将内存中的对象写到目的设备上。比如硬盘。
*/
FileOutputStream fos = new FileOutputStream("temp\\obj.object");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(new Person("mazi",23));
oos.close();
}
public static void readObj() throws IOException, ClassNotFoundException {
FileInputStream fis = new FileInputStream("temp\\obj.object");
ObjectInputStream ois = new ObjectInputStream(fis);
Object obj = ois.readObject();
Person p = (Person)obj;
System.out.println(p.getName()+":"+p.getAge());
ois.close();
}
public class Person implements Serializable {
/**
*
*/
private static final long serialVersionUID = 12367890L;
private static String name;
private transient/*瞬态*/ int age;
public Person() {
super();
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
对象的序列化是要将对象持久存放在设备中
ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
如果可序列化类未显式声明 serialVersionUID,则序列化运行时将基于该类的各个方面计算该类的默认 serialVersionUID 值,如“Java(TM) 对象序列化规范”中所述。不过,强烈建议 所有可序列化类都显式声明 serialVersionUID 值,原因是计算默认的 serialVersionUID 对类的详细信息具有较高的敏感性,根据编译器实现的不同可能千差万别,这样在反序列化过程中可能会导致意外的 InvalidClassException。因此,为保证 serialVersionUID 值跨不同 java 编译器实现的一致性,序列化类必须声明一个明确的 serialVersionUID 值。还强烈建议使用 private 修饰符显示声明 serialVersionUID(如果可能),原因是这种声明仅应用于直接声明类 -- serialVersionUID 字段作为继承成员没有用处。数组类不能声明一个明确的 serialVersionUID,因此它们总是具有默认的计算值,但是数组类没有匹配 serialVersionUID 值的要求。
瞬态
RandomAccessFile
通过skipBytes(int x),seek(int x)来达到随机访问
通常,如果此类中的所有读取例程在读取所需数量的字节之前已到达文件末尾,则抛出 EOFException(是一种 IOException)。如果由于某些原因无法读取任何字节,而不是在读取所需数量的字节之前已到达文件末尾,则抛出 IOException,而不是 EOFException。需要特别指出的是,如果流已被关闭,则可能抛出 IOException。
/*
* RandomAccessFile:
* 1,既可以读取,有可以写入。
* 2,只对文件操作。
* 3,内部维护了一个大型的byte数组,将字节输入流和字节输出流进行封装。
* 4,通过索引的方式对数组中的元素进行操作,获取和设置索引的方法是getFilePointer,seek。
* 5,随机的访问的原理:就是通过操作索引的方法对指针进行自定义的指定位置来进行读写。
*
* 对于被随机读取的数据最好有规律。
*/
构造方法摘要
RandomAccessFile(File file, String mode)
创建从中读取和向其中写入(可选)的随机访问文件流,该文件由 File 参数指定。
RandomAccessFile(String name, String mode)
创建从中读取和向其中写入(可选)的随机访问文件流,该文件具有指定名称。
mode 参数指定用以打开文件的访问模式。允许的值及其含意为: "rws" 和 "rwd" 模式的工作方式极其类似 FileChannel 类的 force(boolean) 方法,分别传递true 和false 参数,除非它们始终应用于每个 I/O 操作,并因此通常更为高效。如果该文件位于本地存储设备上,那么当返回此类的一个方法的调用时,可以保证由该调用对此文件所做的所有更改均被写入该设备。这对确保在系统崩溃时不会丢失重要信息特别有用。如果该文件不在本地设备上,则无法提供这样的保证。 "rwd" 模式可用于减少执行的 I/O 操作数量。使用 "rwd" 仅要求更新要写入存储的文件的内容;使用 "rws" 要求更新要写入的文件内容及其元数据,这通常要求至少一个以上的低级别 I/O 操作。 |
管道流
PipedInputStream和PipedOutputStream
输入输出可以直接进行连接,通过结合线程使用
可以将管道输出流连接到管道输入流来创建通信管道。管道输出流是管道的发送端。通常,数据由某个线程写入 PipedOutputStream 对象,并由其他线程从连接的 PipedInputStream 读取。不建议对这两个对象尝试使用单个线程,因为这样可能会造成该线程死锁。如果某个线程正从连接的管道输入流中读取数据字节,但该线程不再处于活动状态,则该管道被视为处于 毁坏 状态
管道输入流应该连接到管道输出流;管道输入流提供要写入管道输出流的所有数据字节。通常,数据由某个线程从 PipedInputStream 对象读取,并由其他线程将其写入到相应的 PipedOutputStream。不建议对这两个对象尝试使用单个线程,因为这样可能死锁线程。管道输入流包含一个缓冲区,可在缓冲区限定的范围内将读操作和写操作分离开。如果向连接管道输出流提供数据字节的线程不再存在,则认为该管道已损坏。
public class PipedStreamDemo {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
PipedInputStream in = new PipedInputStream();
PipedOutputStream out = new PipedOutputStream();
in.connect(out);
new Thread(new Input(in)).start();
new Thread(new Output(out)).start();
}
}
class Input implements Runnable{
private PipedInputStream in;
public Input(PipedInputStream in) {
super();
this.in = in;
}
@Override
public void run() {
byte[] buf = new byte[1024];
int len;
try {
len = in.read(buf);//阻塞。
String str = new String(buf,0,len);
System.out.println(str);
} catch (IOException e) {
e.printStackTrace();
}
}
}
class Output implements Runnable{
private PipedOutputStream out;
public Output(PipedOutputStream out) {
super();
this.out = out;
}
@Override
public void run() {
try {
out.write("哈哈哈,我来了!".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
}
操作基本数据类型
DataInputStream与DataOutputStream
write(int):将一个整数的四个字节中的最低字节写入到目的地。
* print(int);将一个整数的表现形式写入到目的地。你写的是什么,到目的地就是什么。
* writeInt(int);将一个整数的四个字节写入到目的地。保证数据字节的原样性。
/*
* 操作基本数据类型值的流对象。
*
*
*
*
*/
public static void readData() throws IOException {
FileInputStream fis = new FileInputStream("temp\\data.txt");
DataInputStream dis = new DataInputStream(fis);
int num = dis.readInt();
System.out.println(num);
dis.close();
}
操作字节数组
关闭 ByteArrayInputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。
对应的源设备是内存中的字节数组
关闭 ByteArrayOutputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException
对应目的地是内存
ByteArrayInputStream bis = new ByteArrayInputStream("abcdef".getBytes());
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int ch = 0;
while((ch=bis.read())!=-1){
bos.write(ch);
}
System.out.println(bos.toString());
试用场景 用流的思想去操作数组 不用判断溢出等操作 而且数组长度可变 可以缓存一些数据
CharArrayReader与CharArrayWriter
操作字符串
StringReader 与 StringWriter