io流
1.按照操作数据类型分为字节流和字符流
2.按流向分为输出流和输入流
字节流的抽象基类
InputStream OutputStream
字符流的抽象基类
Reader Writer
常用io字符流类
1.
FileWriter fw = new FileWriter();//自动创建文件,会抛出异常,如果文件存在会覆盖
write(String)方法向中写入数据,也会抛出异常
fflush()方法刷新流,将数据写入对象中,
或者直接用close()方法关闭流,也有刷新作用。
FileWriter fw = new FileWriter(“”,true);第二个参数,表示接下来的操作都是续写文件
write方法常用传入参数 (String) (buf,0,num)
1.1
处理IO异常标准格式
FileWriter fw = null;
try
{
fw = new FileWriter();// 如果在try中定义,作用域会变小,所以在外部定义,然后初始 化
fw.write();
}
catch(IOException ex)
{
System.out.println(ex.toString());
}
finally
{
try
{
if(fw!=null)//如果上面文件创建失败就不用关闭了
{
fw.close();
}
}
catch(IOException e)
{
System.out.println(e.toString());
}
}
2.
FileReader fr = new FileReader();//如果文件不存在就会报错
fr.read();//每次读取一个文件字符,返回字符的int值,如果文件 结束返回-1,所以返回值不等于-1可以作为循环读取整个文件的条件 !一个程序中,每次自动接着上次的位置向下读
read(buf) read方法传入一个字符数组参数,则文件里的数组大小的内容会读入到数组中并返回实际读入的字符个数,读到末尾也是返回-1
read方法是不用刷新的
根据这个特性可写成新的循环条件
while((num = fr.read(buf))!=-1)
{
System.out.print(new String(buf,0,num));//这里最好不要用println可能会形成不想要的换行
}
如果可读取字符个数小于数组长度,则read方法会把剩下字符读完,还是返回读入字符个数,下次再读取时,才会返回-1.
这种一次读取多个字符的read方法比较常用。
运用上面的知识可以写一个复制文件的例子
public class Demo {
public static void main(String[] args) {
// TODO Auto-generated method stub
FileReader fr = null;
FileWriter fw = null;
try
{
fr = new FileReader("C:\\Users\\dellpc\\Desktop\\buf.txt");
fw = new FileWriter("F:\\test.txt");
char[] buf = new char[1024];
int num = 0;
while((num = fr.read(buf))!=-1)
{
fw.write(buf,0,num);
}
}
catch (IOException x)
{
System.out.println(x.toString());
}
finally
{
if(fr!=null )
{
try
{
fr.close();
}
catch(IOException x)
{
System.out.println(x.toString());
}
}
if(fw!=null)
{
try
{
fw.close();
}
catch(IOException x)
{
System.out.println(x.toString());
}
}
}
}
}
3.
BufferedWriter //缓冲区写入
需要封装流对象 BufferedWriter fw = new BufferedWriter(new FileWriter());
使用方法和FileWriter基本相同 每次写入后要刷新,fflush();
fw.newLine();开启新的一行,缓冲区才有的方法,跨平台方法,和readLine一样缓冲区特有方法
关闭缓冲区fw.close()其实就是关闭流对象
BufferedReader //缓冲区读取
也需要封装流对象 BufferedReader fr = new BufferedReader(new FileReader());
使用方法和FileReader基本相同,不过有一个特别的方法readLine();
一次可以读取文件的一行,返回读取到的字符串,读到流(文件)的末尾就返回null,但是返回的字符串中不包括换行符,用print打印出来就可以知道
readLine()读取文件例子
public static void main(String[] args) throws Exception{
BufferedReader fr = new BufferedReader(new FileReader("C:\\Users\\dellpc\\Desktop\\buf.txt"));
String line = null;
int num = 0;
char[] buf = new char[1024];
while((num = fr.read(buf))!=-1)
{
System.out.print(new String(buf,0,num));
}
fr.close();
}
}
readLine()是读取数据最为方便的一种方法
为什么加入缓冲技术,是为了更有效率,其是缓冲技术就是在普通的操作数据的基础上加入了数组,将一部分数据先放到数组中,再整体操作。
运用缓冲区技术实现文件复制
public class Demo {
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
BufferedReader fr = new BufferedReader(new FileReader("C:\\Users\\dellpc\\Desktop\\buf.txt"));
BufferedWriter fw = new BufferedWriter(new FileWriter("F:\\test.txt"));
String str = null;
while((str = fr.readLine())!=null)
{
fw.write(str);
fw.newLine();
fw.flush();
}
fw.close();
}
}
用到newLine()就是因为readLine()不返回一行的换行符导致的。
常用io字节流
1.
FileOutputStream
1.1使用方法
FileOutputStream fos = new FileOutputStream(“”);
write(char[]buf)方法,常用的传入参数是二进制数组,我们想传入字符串时,可以调用字符串的getByte()方法
字符流类内部其实使用的也是字节流,先把字符存到二进制数组中,通过刷新flush()方法完成写入,所以直接用字节流类write()方法时,不需要flush()刷新
close()方法
2.
FileInputStream
2.1使用方法
FileInputStream fis = new FileInputStream(“”);
read方法和BufferedReader一样,传入数组当参数时要传入字节数组byte[];
2.2InputStream字节流的特殊方法
available(),获取数据大小,返回整数值,如果用FileInputStream打开一个英文文本文件,可以先用available()方法获取文件大小,这是就可以申请一个大小刚好的二进制数组byte[] buf = new byte[fis.available()];就不用用read方法循环读取了。直接读取一次就是整个文本。
(byte[]数组一个元素占一字节即8bit,这也是文本中一个英文字符所占空间大小)
2.3字节流复制文件的例子
public class Demo {
public static void main(String args[]) throws Exception
{
FileOutputStream fos = null;
FileInputStream fis = null;
try
{
fos = new FileOutputStream(“F:\333.xlsx”);
fis = new FileInputStream(“F:\15003401.xlsx”);
byte[] buf = new byte[17496];
int len =0;
int num = fis.available();
System.out.println(num);
while((len = fis.read(buf))!=-1)
{
fos.write(buf,0,len);
}
}
catch (Exception x)
{
System.out.println(x.toString());
}
finally
{
if(fos!=null)
{
try
{
fos.close();
}
catch(Exception x)
{
}
}
if(fis!=null)
{
try
{
fis.close();
}
catch(Exception x)
{
}
}
}
}
}
3.BufferedInputStream
字节流缓冲区
4.BufferedOutputStream
番外
1.自定义字节流读取键盘输入
class MyBufferedInputStream
{
private InputStream in;
private byte[] buf = new byte[1024];
private int pos =0,count = 0;
MyBufferedInputStream(InputStream in)
{
this.in = in;
}
public int myRead() throws Exception//一次读入一个字节从缓冲区
{
if(count == 0)
{
count = in.read(buf);
if(count<0)
{
return -1;
}
pos = 0;
byte b = buf[pos];
count--;
pos++;
return b&255;
}
else if(count>0)
{
byte b = buf[pos];
count--;
pos++;
return b&255;
}
return -1;
}
public void myClose() throws Exception
{
in.close();
}
}
public class Demo {
public static void main(String args[]) throws Exception
{
InputStream in = System.in;
StringBuilder sb = new StringBuilder();
while(true)
{
int ch = in.read();
if(ch=='\r')
{
continue;
}
if(ch == '\n')
{
String s = sb.toString();
if("over".equals(s))
{
break;
}
else
{
System.out.println(s);
sb.delete(0,sb.length());
}
}
else
{
sb.append((char)ch);
}
}
}
}
键盘录入不能在程序里实现结束,需要手动按ctrl+c才能结束。字节流read方法返回的是一字节二进制的整数形式,因为如果返回byte形式8个二进制就等于-1,和结束标志冲突了,返回整数形式时也需要一点修改,只保留最低8位,所以和255进行且&运算。
5.字节转换流
InputStreamReader = new InputStreamReader(new InputStream())
OutputStreamWriter = new OutputStream(new OutputStream());
这样就可以调用一些字符流方法
还可以进一步封装成BufferedReader与BufferedWriter方法,比如readLine和newLine
5.1常用的键盘录入方法
public class Demo {
public static void main(String args[]) throws Exception
{
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
String line = null;
while((line = bufr.readLine())!=null)
{
//System.out.println(line);
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
bufr.close();
}
}
如果用System.in封装的字节流只能一个一个读取.用上文的bufr单独去键盘录入更为方便,一次能读取一行。
番外
流的操作很灵活,但是流的对象很多,要灵活运用流,就要
1.明确源和目的
比如要把一个文本打印到控制台上,用到转化流的话,可以这样定义流的变量
BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileInputStream("C:\\Users\\dellpc\\Desktop\\buf.txt")));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
而如果想把键盘录入内容写到文本里的时候可以这样
BufferedReader bufr = new BufferedReader(System.in);
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new InputStreamReader(new FileInputStream("C:\\Users\\dellpc\\Desktop\\buf.txt"))));
2.明确操作对象
是不是纯文本?
是:字符流
不是:字节流.
3.体系明确后,明确具体操作对象
通过设备来进行区分
原设备:内存,硬盘(文件),键盘
目的设备:内存,硬盘(文件),控制台