IO流
1、IO流概述
java的IO流就是实现输入\输出的基础,它可以方便的实现数据的输入\输出操作,java中把不同的输入\输出源对象表述为“流”,通过流的方式允许java程序使用相同的方式来访问不同的输入\输出。stream是从源到接受的有序数据。1.1 流的分类
输入流:InputStream和Reader 输出流:OutputStream和Writer字节流和字符流的区别很简单,他们的用法几乎完全一样,区别就在于字节流和字符流所操作的数据单元不同:字节流操作的最小数据单元是8位的字节,而字符流操作的最小数据单元式16位的字符 。
2 InputStream和Reader
InputStream有如下的方法:read():从输入流中读取单个字节,返回的就是所读取的字节----直接转换成int型
read(byte[] buff):将所读取的数据直接装进buff数组中,并且每次所读取到的数据不能超过数组的 长度。:
read(byte[] buff,int off,int len)将所读取的数据直接装进数组中,每次读取最多的为len长度的数据。
Read有如下的方法:
read():从输入流中读取单个字符,返回的就是所读取的字符----直接转换成int型
read(char[] buff):将所读取的数据直接装进buff数组中,并且每次所读取到的数据不能超过数组的长度。:
read(char[] buff,int off,int len)将所读取的数据直接装进数组中,每次读取最多的为len长度的数据。
他们分别就是有一个常用的实现类,FileInputStream和FileReader
现在我们通过例子体验一下他们各自的读取过程:
//字符流的读取过程
class FileReaderDemo
{
public static void main(String[] args)throws IOException
{
FileReader fr = new FileReader("Demo.txt");//这个关联文件必须存在
//fr.read() 这个方法是一次读取一个字符,返回值为int型 当为-1时。表示已经读取完
int ch=0;
while((ch=fr.read())!=-1)
{
System.out.println("ch="+(char)ch);//因为read方法读取的是char所以应该强转
}
}
}*/
//读取的第二种方法
class FileReaderDemo
{
public static void main(String[] args)throws IOException
{
FileReader fr = new FileReader("Demo.txt");
//fr.read(数组),此方法就是讲读到的数据读入到数组中,返回值为int
//表示读入到数组中的元素的个数,当为-1,表示没有读到数据
char[] buff =new char[1024];
int num=0;
while((num=fr.read(buff))!=-1)
{
System.out.println(new String(buff,0,num));
}
}
}
//字节流的读取过程
class InputStreamDemo
{
public static void main(String[] args)throws Exception
{
FileInputStream fis=new FileInputStream("Demo.java");//关联一个文件,这个文件必须存在
int[] buff=new int[1024];
int len=0;
while((len=fis.read(buff))!=-1)
{
System.out.println(new String(buff,0,buff.length));
}
}
}
3 OutputStream和Writer
这两个输出流的方法基本和读取流的方法就是一样的,只不过就是把他们读的方法改写成写就行。4 转换流和缓冲流
转化流:InputStreamReader和OutputStreamWriter的出现架起了字符流和字节流之间连接的桥梁缓冲流:BufferedReader和BufferedWriter的出现大大提高了流的操作效率,也引出了装饰设计模式的概念。
现在我们就通过例子,体验一下,这两个新增流的特点以及好处。
将D盘下的一个文件拷贝到制定目录下
//原理:就是读取 再去复制
import java.io.*;
class CopyTest
{
public static void main(String[] args)
{
COPY();
}
/*public static void COPY()throws IOException 未使用缓冲区技术
{
FileWriter fw=new FileWriter("cpoy.txt");//创建文件拷贝目的
FileReader fr=new FileReader("D:\\java重点\\整理JAVASE.java");//读取要拷贝文件
int num=0;
char[] ch=new char[1024];
while((num=fr.read(ch))!=-1)
{
fw.write(ch,0,num);
}
fr.close();
fw.close();
}*/
public static void COPY() //使用缓冲区技术
{ BufferedWriter bufw=null;
BufferedReader bufr=null;
try
{
bufw=new BufferedWriter(new FileWriter("copy1.text"));//目标文件和流相关联
bufr=new BufferedReader(new FileReader("D:\\java重点\\整理JAVASE.java"));
String line=null;
while((line=bufr.readLine())!=null)//字符流缓冲区加入了一次读取一行的方法
{
bufw.write(line);
bufw.newLine();//此处必须换行,因为缓冲流写数据的时候没有换行的功能。
bufw.flush();//将流中的数据,输出到目标文件中。
}
catch(IOException e)
{
System.out.println(e.toString());
}
finally
{
try
{
if(bufr!=null)
bufr.close();
}
catch(IOException e)
{
System.out.println(e.toString());
}
try
{
if(bufw!=null)
bufr.close();
}
catch(IOException e)
{
System.out.println(e.toString());
}
}
}
通常来说,我们都是认为字节流的功能比字符流的功能强大,因为计算机里面的数据都是二进制的,而字节流可以处理所有的二进制文件--但是,现在的问题是如果我们使用字节流来处理文本文件的时候,我们就需要将字节转换成字符,这就增加了编程的难度。所以,我们现在就产生了一个规则:如果需要进行输入和输出的内容是文本内容,则应该考虑使用字符流,如果操作的是二进制的内容,我们就是需要使用字节流。这就是毕老师总结的看元和目的的方法。
5、其他常用的流
在IO流这个大框架中,我们还会用到其他的流对象。例如:
5.1 PrintWriter: 1,File对象 2,String字符集 3,字符输出流Writer 4,字符输出流 Outputstream
PrintStream: 1,File对象 2,String字符集 3,字符输出流 Outputstream
以上两个打印流是最经常用的。
5.2 序列流:SequenceInputStream---就是将多个流对象合并成为一个流对象,其构造函数可以传入两个InputStream ,也可以传入Enumeration。例如,可以看看一个文件的切割与合并:
import java.io.*;
import java.util.*;
class SpilitDemo
{
public static void main(String[] args)throws IOException
{
//spilitFile();
merger();
}
public static void spilitFile()throws IOException//切割文件
{
FileInputStream fis = new FileInputStream("1.jpg");
FileOutputStream fos = null;
byte[] arr =new byte[1024*1024];
int num=0;int count=0;
while((num=fis.read(arr))!=-1)
{
fos=new FileOutputStream((count++)+".part");
fos.write(arr,0,num);
fos.close();
}
fis.close();
}
public static void merger()throws IOException//合并文件
{
List<FileInputStream> list= new ArrayList<FileInputStream>();
for(int x=0;x<3;x++)
{
list.add(new FileInputStream(x+".part"));
}
final Iterator<FileInputStream> it = list.iterator();
Enumeration<FileInputStream> en = new Enumeration<FileInputStream>()
{//用枚举的方式
public boolean hasMoreElements()
{return it.hasNext();}
public FileInputStream nextElement()
{return it.next();}
};
SequenceInputStream si=new SequenceInputStream(en);//将枚举对象传入其中
FileOutputStream fos = new FileOutputStream("4.jpg");
int line=0;byte[] buf=new byte[1024*1024];
while((line=si.read(buf))!=-1)
{
fos.write(buf);
}
fos.close();si.close();
}
}
5.3 管道流和Properties
管道流集合中和io流相结合的是Properties,在io流中和多线程相结合的是管道路其他io流的读取和写入,必须要一个中转站数组或者缓冲区才能相结合管道流是不需要中转站的流而直接相结合的他的读取和写入时需要多线程的 要不然就会发生死锁现象
import java.io.*;
import java.util.*;
class Read implements Runnable
{
private PipedInputStream in;
Read(PipedInputStream in)
{
this.in=in;
}
public void run()
{
try
{
byte[] buf=new byte[1024];
int num=0;
while((num=in.read(buf))!=-1)
{
String s=new String(buf,0,num);
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("读到了数据,谢谢".getBytes());
out.close();
}
catch(IOException e)
{
throw new RuntimeException("结束读取");
}}
}
class PipedDemo
{
public static void main(String[] args)throws IOException
{
PipedInputStream pi=new PipedInputStream();
PipedOutputStream po=new PipedOutputStream();
pi.connect(po);
Read r=new Read(pi);
Write w=new Write(po);
new Thread(r).start();//开启线程
new Thread(w).start();
}
}
以上都是我们在平时的开发程序时候能够经常用到的流对象,我们应该掌握其用法。
6、File类和RandomAccessFile类
在平时的程序中,我们要关联一个文件的时候,假如没有文件我们还会用到File类。例如:File file=new File("Demo");
if(!file.exixs()){file.creatNewFile();}然后再将其和流相关联,至于RandomAccessFile该对象不是流体系中的一员,其封装了字节流,同时还封装了一个缓冲区,通过内部的指针来操作字符数组中的数据,其特点就是:该对象只能操作文件,所以构造函数接受两种类型的参数:字符串文件路径、File对象该对象既可以对文件进行读操作,也可以进行写操作,在进行对象的实例化可指定操作模式(r.w)。需要注意的是:该对象在实例化的时候,如果要操作的文件不存在,会自动创建文件;如果文件存在,写数据未指定位置的时候会从头开始写,并覆盖原有的内容。