---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------
IO流用来处理设备之间的数据传输 ,Java对数据的操作是通过流的方式 。 Java用于操作流的对象都在IO包中。
流按操作数据分为两种:字节流与字符流;-------- 流按流向分为:输入流,输出流。
IO流常用类:
字节流的抽象基类: InputStream ,OutputStream。
字符流的抽象基类: Reader ,Writer。
注:由这四个类派生出来的子类名称都是 以其父类名作为子类名的后缀。如:InputStream的子类FileInputStream。 • 如:Reader的子类FileReader。
一、字符流:
FileWriter创建写入文件示例
import java.io.*;
class FileWriterDemo
{
public static void main(String[] args) throws IOException
{
//第一步:创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件,而且该文件会被创建在指定目录下
//如果该文件存在,将被覆盖,该步骤也就是在明确数据存放的目的地
//FileWriter fw = new FileWriter("demo.txt");
//传递一个true参数,代表不覆盖已有的文件。并在已有文件的末尾处进行续写
//FileWriter fw = new FileWriter("demo.txt" true);
//调用write方法,将字符串写入到流中。
fw.write("abced"); //这一步不会直接写硬盘而是写入到流当中直到执行flush方法刷新数据才会写入硬盘
//刷新流对象中缓冲的数据,将数据刷到目的地
fw.flush();
fw.close(); //关闭流,但是关闭之间会刷新内部缓冲中的数据
}
}
FileReader读取流示例
import java.io.*;
class FileReaderDemo
{
public static void main(String[] args) throw IOException
{
//创建一个文件读取流对象,和指定名称的文件相关联,要保证文件存在,如果不存在会发生FileNotFoundException
FileReader fr = new FileReader("demo.txt"); //文件中内容为"abcdefg"
//调用读取流对象的read方法。read方法每次读取一个字符,而且会自动往下读取,并且把读取到的字符以整型返回
//如果读取到文件末尾则返回-1,根据这个特性可以使用循环的方式使用此方法。
//第一种方式:
int ch = 0;
while((ch = fr.read()) != -1)
System.out.println((char)ch);
//第二种方式:
//定义一个字符数组,用于存储读到的字符,并返回读到的个数。
char[] buf = new char[3];
int num = fr.read(buf); //读流数据到数组中
System.out.println("num"+num +"...."+new String(buf)); //输出num=3...abc
int num1 = fr.read(buf);
System.out.println("num1"+num1+ "...."+new String(buf)); //输出num1=3...def
int num2 = fr.read(buf);
System.out.println("num2"+num2+ "...."+new String(buf)); //输出num2=1...gef 读了一个元素改变第一个元素后面元素不变
int num3 = fr.read(buf);
System.out.println("num2"+num2 +"...."+new String(buf)); //输出num3=-1...gef 文件尾返回-1数组内容不改变
}
}
字符流的缓冲区 :
缓冲区的出现提高了对数据的读写效率,缓冲区对应的类:
1、BufferedWriter:
2、BufferedReader:
缓冲区必须结合流才能使用,其在流的基础上对流的功能进行了增强,所以在创建缓冲区之前必须要先有流对象,在使用中只需要将需要使用缓冲区的流对象传递给缓冲区构造函数就可以了,在使用过程中一定要及时刷新数据,使用结束后关闭缓冲区就是在关闭缓冲区中对应的流对象。
readLine方法的原理:
无论是读一行,获取多个字符,最终都是在硬盘上一个一个读取,所以都是使用read方法一次读一个的方法。
装饰设计模式:
当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能,那么自定义的该类称为装饰类。
装饰类通常会通过构造方法接受被装饰的对象,并基于被装饰的对象的功能,提供更强的功能。
装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强的功能,所以装饰类和被装饰类通常是都属于一个体系中。
字节流:InputStream OutputStream
FileInputStream FileOutputStream BufferedInputStream BufferedOutputStream
流对象的基本规律:在使用中最纠结的就是使用哪个对象来完成操作。
1、明确源和目的。
源:输入流。InputStream Reader
目的:输出流。OutputStream Writer
2、明确操作的数据是不是纯文本。
3、当体系明确后,再明确使用哪个具体的对象。是:字符流
不是:字节流。
转换流通过设备来进行区分:
源设备:内存、硬盘、键盘
目的设备:内存、硬盘、控制台。
InputStreamReader,OutputStreamWriter
转换流的由来:字符流与字节流之间的桥梁,为了 方便字符流与字节流之间的操作
转换流的应用:字节流中的数据都是字符时,转成字符流操作 更高效。 例程:标准输入输出。
System类中的字段:in,out。
它们各代表了系统标准的输入和输出设备。 默认输入设备是键盘,输出设备是显示器。
System.in的类型是InputStream.
System.out的类型是PrintStream是 OutputStream 的子类FilterOutputStream 的类
标准输入输出流示例:
例:获取键盘录入数据,然后将数据流向显示器,那么显示器就是目 的地。通过System类的setIn,setOut方法对默认设备进行改变。
System.setIn(new FileInputStream(“1.txt”));//将源改成文件1.txt。
System.setOut(new FileOutputStream(“2.txt”));//将目的改成文件2.txt
因为是字节流处理的是文本数据,可以转换成字符流,操作更方便。
BfferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
FILE类:
用来将文件或者文件夹封装成对象,方便对文件与文件夹的属性信息进行操作,FILE对象可以作为参数传递给流的构造函数。
File类的常见方法:
1、创建:boolean createNewFile():在指定位置创建文件,如果该文件已经存在则不创建,返回false。和输出流不一样,输出流一建立就创建文件,而且会覆盖。
mkdir():创建目录。mkdirs()创建多级目录
2、删除:boolean delete()删除失败返回false,void deleteOnExit()在程序退出时删除指定文件。
3、判断:boolean exists():文件是否存在。isFIle();isDIrectory(); isHidden();是否是隐藏文件;isAbsolute();是否是绝对路径
4、获取信息:getName(); getPath()返回对象封装的路径(相对路径或绝对路径);
getParent()返回的是绝对路径中的文件父目录,如果对象封装为相对路径会返回null如果相对路径中有上层目录那么该目录就是返回结果;
getAbsolutePath()获取绝对路径,
lastModified()获取程序最后的修改时间。
File示例:列出指定目录下文件或者文件夹,包含子目录中的内容。
import java.io.*;
class FileDemo
{
public static void main(String[] args)
{
File dir = new File("d:\\test");
showDir(dir);
}
//showDir方法列出指定目录下所有的文件及子目录下的所有文件
public static void showDir(File dir)
{
System.out.println(dir); //首先输出目录
File[] files = dir.listFiles(); //返回目录下所有文件及目录的File对象
for(int x=0; x<files.length; x++)
{
if (files[x].isDirectory()) //如果是目录则递归调用函数继续遍历下层目录
showDir(files[x]);
else
System.out.println(files[x]);//是文件则输出
}
}
}
删除一个带内容的目录:删除目录是按照从里往外的原则,必须先删除最里层的文件然后是目录以此类推,可以使用递归的方法实现操作。
Properties是hashtable的子类,它具备map集合的特点,而且他里面存储的键值对都是字符串,是集合中和IO相结合的集合容器,该对象的特点:可以用于键值对形式的配置文件。
Properties中常用的方法:
load(Reader reader)
按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。
store(Writer writer,String comments)
以适合使用 load(Reader)
方法的格式,将此Properties
表中的属性列表(键和元素对)写入输出字符。
list(PrintStream out)
将属性列表输出到指定的输出流。
setProperty(String key,String value)
调用 Hashtable 的方法 put
。
Properties的使用示例:
import java.io.*;
import java.util.*;
//使用properties类对配置文件进行存取
class PropertiesDemo
{
public static void main(String[] args) throws IOException
{
runCount();
}
public static void runCount()throws IOException
{
Properties pro = new Properties();
File file = new File("c:\\count.ini");
//当配置文件不存在时就创建该文件
if (!file.exists())
file.createNewFile();
//加载配置文件
FileInputStream fis = new FileInputStream(file);
pro.load(fis);
int count = 0;
//获取times的值
String value = pro.getProperty("times");
if (value != null)
{
count = Integer.parseInt(value);
//如果已经到达使用次数就提示用户后直接退出函数
if(count >= 5)
{
System.out.println("请注册后再使用");
return ;
}
}
count++;
//把使用次数加一后写入文件
pro.setProperty("times",count+"");
FileOutputStream fos = new FileOutputStream(file);
pro.store(fos,"");
fos.close();
fis.close();
}
}
IO包中的其他类:
打印流:提供了打印方法,可以将各种数据类型的数据都原样打印。
字节打印流:
PrintStream:构造函数可以接收的参数类型:1、file对象(file)。2、字符串路径(String)。3、字节输出流(OutputStream)。
字符打印流:
PrintWriter:构造函数可以接收的参数类型:1、file对象(file)。2、字符串路径(String)。3、字节输出流(OutputStream),4、字符输出流(Writer)。
序列流SequenceInputStream对多个流进行合并。
直接操作对象的流
ObjectInputStream与ObjectOutputStream被操作的对象需要实现Serializable(标记接口)
在对对象序列化的时候,类中的静态成员不会被序列化,如果非静态成员不想被序列化可以用transient修饰:transient int age;
//创建一个对象输出流,可以把指定对象输出的obj.txt文件
ObjectOutputStream oos =
new ObjectOutputStream(new FileOutputStream("obj.txt")
//把对象p写入到文件obj.txt
//在执行操作之前写入的对象的类必须实现Serializable
oos.writeObject(new Person("lisi",39))
管道流:
PipedInputStream和PipedOutputStream:管道输入流应该连接到管道输出流;管道输入流提供要写入管道输出流的所有数据字节。通常,数据由某个线程从PipedInputStream
对象读取,并由其他线程将其写入到相应的PipedOutputStream
。不建议对这两个对象尝试使用单个线程,因为这样可能死锁线程。
RandomAccessFile:随机访问文件,自身具备读写的方法。 通过skipBytes(int x),seek(int x)来达到随机访问,而且该对象的构造函数要操作的文件会自动创建,如果存在不会覆盖。
操作基本数据类型:如果模式为只读r。不会创建文件,会去读取一个已经存在的文件,如果文件不存在会异常。
如果模式为rw,而且该构造器指定的文件不存在就会创建该文件,如果存在也不会覆盖该文件。
该类不算是IO体系中的子类,而是直接继承自Object。它是io包中成员。具备读写功能,内部封装了一个数组,而且通过指针对数组进行操作。
通过getFilePointer获取指针位置,通过seek改变指针的位置。
seek(long pos)pos
- 从文件开头以字节为单位测量的偏移量位置,在该位置设置文件指针。skipBytes(int n)尝试跳过输入的n
个字节以丢弃跳过的字节。 只能往后前跳,不能往后跳,而seek可以往后跳其实读写的原理就是内部封装了字节输入流和输出流。
通过构造函数可以看出,该类只能操作文件。
DataInputStream和DataOutputStream
操作字节数组
ByteArryInputStream和ByteArrayOutputStream;
ByteArrayInputStream
包含一个内部缓冲区,该缓冲区包含从流中读取的字节。内部计数器跟踪read
方法要提供的下一个字节。关闭 ByteArrayInputStream 无效。这两个对象都不涉及底层资源所以不需要close,即使此类中的方法在关闭此流后仍可被调用,而不会产生任何IOException。
在构造的时候,需要接收数据源,而且数据源是一个字节数组。
public class ByteArrayOutputStream extends OutputStream此类实现了一个输出流,其中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。可使用
toByteArray()
和toString()
获取数据。在构造的时候不用定义数据目的,该对象中已经内部封装了一个可变长度的字节数组,这就是数据目的地。
操作字符数组:
CharArrayReader和CharArrayWrite
操作字符串:
StringReader和StringWriter
字符编码:计算机只能识别二进制数据,早期由来是 电信号。 为了方便应用计算机,让它可以识别各个 国家的文字。就将各个国家的文字用数字来表示,并一 一对应,形成一张表。这就是编码表
可以将字符以指定编码格式存储,可以对文本数据指定编码格式来解读,指定编码表的动作由构造函数完成。
字符流的出现为了方便操作字符,更重要的是加入了编码转换。通过子类转换流来完成:
InputStreamReader:
OutputStreamWriter:
在两个对象进行构造的时候加入字符集。
---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------