------- android培训、java培训、期待与您交流! ----------
java_ io(上)
io流是一组有序的数据序列,根据操作的类型,可分为输入流和输出流两种io(Inpout/Output)liu
同了一条通道程序,可以使用这条通道吧源中的字节序列送到目的地,虽然io流经常与词牌文件存取有关,
但是程序的源和目的地也可以是键盘鼠标,内存或者显示器窗口等.
java有数据流处理输入/输出模式,程序与从指定源的输入流中读取源中的数据,源可以是文件.网络.压缩包
或者其他数据
java语言定义了许多专门负责各个方式的输入/输出,这些类都被放在java.io包中.其中所有输入流
类都是抽象类InputStream(字节输入流)或者抽象类Reader(字符输入流)的子类;而所有输出流都是抽象
类OutputStream(字节输出流)或者抽象类Writer(字符流输出流)的子类.
字节流两个基类:
InputStream OutputStream
字符流两个基类:
Reader Writer
注由这四个类派生出来的子类名称都是 以其父类名作为子类名的后缀。
如:InputStream的子类FileInputStream。
如:Reader的子类FileReader。
//------------------------------------------------------------------------
构造方法:
FileWriter:用来写入字符文件的便捷类java.io Writer另请参见:
FileWriter(String fileName, boolean append)
根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象。
FileWriter(File file)
根据给定的 File 对象构造一个 FileWriter 对象。
FileWriter(FileDescriptor fd)
构造与某个文件描述符相关联的 FileWriter 对象。
FileWriter(String fileName)
根据给定的文件名构造一个 FileWriter 对象。
FileWriter(File file, boolean append)
示:fw=new FileWriter("demo.txt",true);//在已有文件续写.如果没有就文件就创建
根据给定的 File 对象构造一个 FileWriter 对象。
常用方法:
void write(String str):写入字符串。
abstract void flush():刷新该流的缓冲
abstract void close():关闭此流,但要先刷新它。
//创建一个FileWriter对象。该对象一被初始化就必须要明确被操作的文件。
//而且该文件会被创建到指定目录下。如果该目录下已有同名文件,将被覆盖。
//其实该步就是在明确数据要存放的目的地。
FileWriter fw = new FileWriter(“Test.txt”);
//调用write方法,将字符串写入到流中。
fw.write("abcde");
//刷新流对象中的缓冲中的数据。
//将数据刷到目的地中。
//fw.flush();
//关闭流资源,但是关闭之前会刷新一次内部的缓冲中的数据。
//将数据刷到目的地中。
//和flush区别:flush刷新后,流可以继续使用,close刷新后,会将流关闭。
fw.close();
ps:\r\n:回车符.在windows里面需要两个代表回车符.在linux系统\n代表回车符.
//-------------------------------------------------------------------------
IO异常的处理方式续写和回车符:
示例:
import java.io.*;
class FileWriterDemo2
{
public static void main(String[] args)
{
FileWriter fw=null;//需要在代码块外边建立引用.
try
{
fw=new FileWriter("demo.txt",true);
fw.write("accd\r\nde");
}
catch (IOException e)
{
System.out.println(e.toString());
}
finally
{
if(fw!=null)//判断fw是否为空.如果输入盘符错误的话.fw会是null;将执行不到close所以要判断
try
{
fw.close();
}
catch (IOException e)
{
System.out.println("关闭资源失败");
}
}
}
}
//---------------------------------------------------------------------
构造方法:
FileReader:用来读取字符文件的便捷类java.io Reader另请参见:
FileReader(File file)
在给定从中读取数据的 File 的情况下创建一个新 FileReader。
FileReader(FileDescriptor fd)
在给定从中读取数据的 FileDescriptor 的情况下创建一个新 FileReader。
FileReader(String fileName)
在给定从中读取数据的文件名的情况下创建一个新 FileReader。
常用方法:
abstract void |close() 关闭该流并释放与之关联的所有资源。
void |mark(int readAheadLimit) 标记流中的当前位置。
boolean |markSupported() 判断此流是否支持 mark() 操作。
int |read() 读取单个字符。
int |read(char[] cbuf) 将字符读入数组。
abstract int |read(char[] cbuf, int off, int len) 将字符读入数组的某一部分。
int |read(CharBuffer target) 试图将字符读入指定的字符缓冲区。
boolean r|eady() 判断是否准备读取此流。
void |reset() 重置该流。
long |skip(long n) 跳过字符。
第一种取出方式:
//创建一个文件赌球流对象,和指定名称的文件相关联.
//要保证该文件时已经存在的,如果不存在,会发生异常FileNotFoundException
FileReader fr=new FileReader("demo.txt");
int ch=0;
/*
调用读取流对象的read方法
read():一次读一个字符,而且会自动往下读.
*/
while((ch=fr.read())!=-1)
{
System.out.println("ch="+(char)ch);
}
/*
while(true)
{
int ch=fr.read();
if(ch==-1)
break;
System.out.println("ch="+(char)ch);
}
*/
第二种出去方式:
fr=new FileReader("FileWriterDemo.java");
//定义一个字符数组.用于存储到字符.
//该read(char[])返回的是读到的个数
char[] buf=new char[1024];
//定义一个变量来记住个数
int num=0;
//用while循环来判断结尾是否读到的个数为-1
while((num=fr.read(buf))!=-1)
{
//打印个数和字符数组.new String(buf,0,num)是Sting类中打印数组从0开始.到nun结束
System.out.print(num+"....."+new String(buf,0,num));
//注意输出语句没加ln.是因为数组的长度是1024,如果到了1024就会换行.所以不加.
}
练习:拷贝文件
/*
需求:拷贝文本文件.
1.在D盘创建一个文件,用于存储c盘文件中的数据
2.定义读取流和c文件箱关联.
3.通过不断的读写完成数据存储.
4.关闭资源
*/
import java.io.*;
class CopyText
{
public static void main(String[] args)
{
copy_2();
}
public static void copy_2()//建立字符数组集体拷贝
{
FileReader fr=null;//在代码块外边给fr初始化.要不然在代码块里面建立对象别的地方会访问不到
FileWriter fw=null;
try
{
fr=new FileReader("MathDemo.java");//建立对象并指定好目录
fw=new FileWriter("MathDemo_copy.txt");
char[] buf=new char[1024];//建立字符数组,用来储存数据
int len=0;//定义一个变量来记住字符数
while((len=fr.read(buf))!=-1)//因为字符数到末尾会是-1.进行判断
{
fw.write(buf,0,len);//写出数据.并从零开始.到字符数那里结束
}
}
catch (IOException e)//路径不存在抛异常
{
throw new RuntimeException("路径不存在");
}
finally
{
try
{
if(fr!=null)//对close判断.是否为空如果建立对象不成功的话close根本不识别.
fr.close();
}
catch (IOException e)
{
System.out.println("写入失败");
}
try
{
if(fw!=null)
fw.close();
}
catch (IOException e)
{
System.out.println("读取失败");
}
}
}
public static void copy_1()//一个字符一个字符的拷贝
{
FileReader fr=null;
FileWriter fw=null;
try
{
fr=new FileReader("SystemDemo.java");
fw=new FileWriter("System_copy.txt");
int ch=0;
while((ch=fr.read())!=-1)
{
fw.write(ch);
}
}
catch (IOException e)
{
throw new RuntimeException("路径不存在");
}
finally
{
try
{
if(fr!=null)
fr.close();
}
catch (IOException e)
{
System.out.println("写入失败");
}
try
{
if(fw!=null)
fw.close();
}
catch (IOException e)
{
System.out.println("读取失败");
}
}
}
}
//--------------------------------------------------------------------------
BufferedWriter类与BufferedReader类
Bufferedwriter类和BufferedReader类分别继承了Reader类和Writer类.这两个类同样具备了内部缓存机制.
可以可进行单位进行输入输出.
在使用BufferedWriter类的Writer()方法时,数据并没有立即写入至输出流中.而是首先进入缓存区中.
如果想理解将缓存区中个的数据写入输出流中,一定要动用flush()方法.
缓冲区的出现提高了对数据的读写效率。
对应类
BufferedWriter
BufferedReader
字符输出流缓冲区:
缓冲区要结合流才可以使用。
在流的基础上对流的功能进行了增强
缓冲区的出现是为了提高流的操作小路而出现的.
所以在创建缓冲区之前,必须要先有流对象.
该缓冲区提供了一个夸平台的换行符.
newLine();
字符读取流缓冲区:
该缓冲区提供了一个一次读一行的方法 readLine,方便与对文本进行数据的获取.
当返回null时候,表示读到文件末尾.
示例:
/*
需求:复制一个java文件
*/
import java.io.*;
class CopyTextBuf
{
public static void main(String[] args)
{
BufferedReader bufr=null;
BufferedWriter bufw=null;
try
{
//为了提高效率.加入缓冲技术,将字符读取流对象作为参数传递给缓冲区的构造函数.
//建立缓冲区,创建流对象和文件相关联的
bufr=new BufferedReader(new FileReader("BufferedReaderDemo.java"));//字符读取流
bufw=new BufferedWriter(new FileWriter("BufferedReaderDemoCopy_1.txt"));//字符输出流
String s=null;//因为读取一行到末尾的时候会返回null.就可以以null作为循环条件来循环
while((s=bufr.readLine())!=null)
{
bufw.write(s);//读取一行.输出一行
bufw.newLine();//换行
}
}
catch (IOException e)
{
throw new RuntimeException("文件路径错误");
}
finally
{
try
{
if(bufr!=null)
bufr.close();
}
catch (IOException e)
{
System.out.println("读取关闭文件失败");
}
try
{
if(bufw!=null)
bufw.close();
}
catch (IOException e)
{
System.out.println("输出关闭文件失败");
}
}
}
}
//-------------------------------------------------------------------
装饰设计模式:
以前是通过继承将每一个子类都具备缓冲功能。
那么继承体系会复杂,并不利于扩展。
现在优化思想。单独描述一下缓冲内容。
将需要被缓冲的对象。传递进来。也就是,谁需要被缓冲,谁就作为参数传递给缓冲区。
这样继承体系就变得很简单。优化了体系结构。
装饰模式比继承
要灵活。避免了继承体系臃肿。
而且降低了类于类之间的关系。
装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强功能。
所以装饰类和被装饰类通常是都属于一个体系中的。
MyReader//专门用于读取数据的类。
|--MyTextReader
|--MyBufferTextReader
|--MyMediaReader
|--MyBufferMediaReader
|--MyDataReader
|--MyBufferDataReader
class MyBufferReader
{
MyBufferReader(MyTextReader text)
{}
MyBufferReader(MyMediaReader media)
{}
}
上面这个类扩展性很差。
找到其参数的共同类型。通过多态的形式。可以提高扩展性。
class MyBufferReader extends MyReader
{
private MyReader r;
MyBufferReader(MyReader r)
{}
}
MyReader//专门用于读取数据的类。
|--MyTextReader
|--MyMediaReader
|--MyDataReader
|--MyBufferReader
LineNumberReader:
BufferedReaderd 的子类,也属于装饰类跟踪行号的缓冲字符输入流。此类定义了方法 setLineNumber(int)
和 getLineNumber(),它们可分别用于设置和获取当前行号.
演示:
FileReader fr=new FileReader("demo.txt");//建立输入流对象于文件相关联
LineNumberReader lnr=new LineNumberReader(fr);//建立缓冲区.
String line =null;
lnr.setLinNumber(100);//设置行号
while((line=lnr.readLine())!=null)
{
System.out.println(lnr.getLineNumber()+":"+line);//获取行号,和打印一行
}
lnr.close
演示:
/*
明白了BufferedReader类中特有方法readLine的原理后,
可以自定义一个类中包含一个功能和readLine一致的方法。
来模拟一下BufferedReader
*/
import java.io.*;
class MyBufferedReader extends Reader
{
private Reader r;
MyBufferedReader(Reader r)//建立构造函数.一开始就要有流
{
this.r = r;
}
//可以一次读一行数据的方法。
public String myReadLine()throws IOException
{
//定义一个临时容器。原BufferReader封装的是字符数组。
//为了演示方便。定义一个StringBuilder容器。因为最终还是要将数据变成字符串。
StringBuilder sb = new StringBuilder();
int ch = 0;
while((ch=r.read())!=-1)
{
if(ch=='\r')
continue;//判断如果是\r的话在运行.判刑下个\n,如果是最后一行了.返回字符串
if(ch=='\n')
return sb.toString();
else
sb.append((char)ch);
}
if(sb.length()!=0)
return sb.toString();
return null;
}
/*
覆盖Reader类中的抽象方法。
*/
public int read(char[] cbuf, int off, int len) throws IOException
{
return r.read(cbuf,off,len) ;
}
public void close()throws IOException
{
r.close();
}
public void myClose()throws IOException
{
r.close();
}
}
class MyBufferedReaderDemo
{
public static void main(String[] args) throws IOException
{
FileReader fr = new FileReader("buf.txt");
MyBufferedReader myBuf = new MyBufferedReader(fr);//自定义的装饰类
String line = null;
while((line=myBuf.myReadLine())!=null)
{
System.out.println(line);
}
myBuf.myClose();//关闭资源
}
}
//---------------------------------------------------------------------------
字节流
基本操作与字符流类相同
但它不仅可以操作字符,还可以操作其他 媒体文件
InputStream类是字节输入流的抽象类,是所有字节流输入流的父类,InputStream类的具体层次结构
InputStream
|--AudioInputStream
|--ByteArrayInputStream
|--FileInputStream
|--BufferedInputStream
|--DataInputStream
|--等等.详情参阅API java.io包中
|--FilterInputStream
|--InputStream
|--ObjectInputStream
|--PipedInputStream
|--SequenceInputStream
|--StringBufferInputStream
常用方法:
int |available() 返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。
void |close() 关闭此输入流并释放与该流关联的所有系统资源。
void |mark(int readlimit) 在此输入流中标记当前的位置。
boolean | markSupported() 测试此输入流是否支持 mark 和 reset 方法。
abstract int| read() 从输入流中读取数据的下一个字节。
int |read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
int |read(byte[] b, int off, int len) 将输入流中最多 len 个数据字节读入 byte 数组。
void|reset() 将此流重新定位到最后一次对此输入流调用 mark 方法时的位置。
long| skip(long n) 跳过和丢弃此输入流中数据的 n 个字节。
OutputStream类是字节输入流的抽象类,次抽象表示输出字节流的所有类的超类.OutputStream
OutputStream
|--ByteArrayOutputStream
|--FileOutputStream
|--BufferedOutputStream
|--DataOutputStream
|--等等.详情参阅API java.io包中
|--FilterOutputStream
|--ObjectOutputStream
|--OutputStream
|--PipedOutputStream
常用方法:
void |close() 关闭此输出流并释放与此流有关的所有系统资源。
void |flush() 刷新此输出流并强制写出所有缓冲的输出字节。
void |write(byte[] b) 将 b.length 个字节从指定的 byte 数组写入此输出流。
void |write(byte[] b, int off, int len) 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
abstract void |write(int b) 将指定的字节写入此输出流。
FileInputStream 与 FileOutputStream 类
FileInputStream类与FileOutputStream类都是用来操作磁盘文件的,如果用户的文件读取需求比较简单,测可以使用FileInputStream类.该类继承自InputStream类
FlieOutputSream类与FileInputStreamLEI对应提供了基本的文件写入能力,FileOutputStream类是OutputStream类的子类.
示例:
/*
需求:拷贝一个图片
1.创建一个字符输入流和图片相关联.
2.用字节写入流对创建图片文件,用于存储到图片数据.
3.通过循环续写,完成数据的存储.
4.关闭资源.
*/
import java.io.*;
class CopyPic
{
public static void main(String[] args)
{
FileInputStream fis=null;
FileOutputStream fos=null;
try
{
fis=new FileInputStream("D:\\2.jpg");//建立字符输入流对象和文件相关联
fos=new FileOutputStream("copy.jpg");//建立字符输出流对象指定路径和文件名字
byte[] buf=new byte[1024];//创建一个字符数组.用来缓存
int num=0;//定义一个变量用于判断结尾处是否是-1
while((num=fis.read(buf))!=-1)
{
fos.write(buf,0,num); //循环一次.字符数组输出一次.
}
}
catch (IOException e)//处理异常
{
throw new RuntimeException("路径错误");
}
finally
{
try
{
if(fos!=null)//判断创建文件失败是否为null;
fos.close();
}
catch (IOException e)
{
System.out.println("输出关闭失败");
}
try
{
if(fis!=null)
fis.close();
}
catch (IOException e)
{
System.out.println("输入关闭失败");
}
}
}
}
//------------------------------------------------------
用缓冲区技术拷贝Mp3
BufferedInputStream buis=null;
BufferedOutputStream buos=null;
try
{
buis=new BufferedInputStream(new FileInputStream("D:\\Maid with the Flaxen Hair.mp3"));
buos=new BufferedOutputStream(new FileOutputStream("copy.mp3"));
int num=0;
while((num=buis.read())!=-1)
{
buos.write(num);
}
}
buis.close();
buos.colse();
//-------------------------------------------------
InputStreamReader和OutputStreamWriter
InputStreamReader :
是字节流通向字符流的桥梁。
每次调用 InputStreamReader 中的一个 read()
方法都会导致从底层输入流读取一个或多个字节。要启用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节。
为了达到最高效率,可要考虑在 BufferedReader 内包装 InputStreamReader。
构造方法:
InputStreamReader(InputStream in)
InputStreamReader(InputStream in, String charsetName)
示例:
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
OutputStreamWriter :
是字符流通向字节流的桥梁:
将要写入流中的字符编码成字节
每次调用 write() 方法都会导致在给定字符(或字符集)上调用编码转换器。在写入底层输出流之前,得到的这些字节将在缓冲区中累积。
为了获得最高效率,可考虑将 OutputStreamWriter 包装到 BufferedWriter 中,以避免频繁调用转换器。
构造方法:
OutputStreamWriter(OutputStream out)
OutputStreamWriter(OutputStream out, String charsetName)
示例:
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
System.in 默认设备为键盘
System.setIn(InputStream in)\\ 重新分配“标准”输入流。
System.out 默认设备为控制台
System. setOut(PrintStream out) \\重新分配“标准”输出流。
PrintStream 的构造方法:
PrintStream(String fileName)\\ 创建具有指定文件名称且不带自动行刷新的新打印流。
---------------------------------------------------------------------
异常的日志信息
printStackTrace()//将此 throwable 及其追踪输出至标准错误流。
printStackTrace(PrintStream s)// 将此 throwable 及其追踪输出到指定的输出流。
示例:
import java.io.*;
import java.util.*;
import java.text.*;
class ExceptionInfo
{
public static void main(String[] args)throws IOException
{
try
{
int[] arr = new int[2];
System.out.println(arr[3]);
}
catch (Exception e)
{
try
{
Date d = new Date();//建立日期类
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//格式化日期
String s = sdf.format(d);
PrintStream ps = new PrintStream("exeception.log");//设置异常文件
ps.println(s);
System.setOut(ps);
}
catch (IOException ex)
{
throw new RuntimeException("日志文件创建失败");
}
e.printStackTrace(System.out);//异常信息
}
}
}
---------------------------------------------------------------------
获取系信息
方法:
list(PrintStream out)// 将属性列表输出到指定的输出流
示例:
import java.io.*;
import java.util.*;
class SystemInfo
{
public static void main(String[] args) throws IOException
{
Properties prop=System.getProperties();
//System.out.println(prop);
prop.list(new PrintStream("sysinfo.txt"));
//Properties中的list方法PrintStream创建具有指定文件名称且不带自动行刷新的新打印流。
}
}