io流在java中与Android中有很大的相似性,我们先看java中的IO流
一, 文件流:
File f = new File("e:" + File.separator + "test.txt");// separator是分割符,适用于不同系统
if (f.exists()) {// f 存在
if (f.isFile()) {// 如果f是文件
// 打印相关信息
System.out.println("文件名称" + f.getName());
System.out.println("文件大小" + f.length());
System.out.println("文件路径" + f.getAbsolutePath());
// 输入流
FileInputStream fis = null;
try {
fis = new FileInputStream(f);
// 通过获得文件大小读取文件
// int lenght = fis.available();//文件的大小
// byte [] bytes = new byte[lenght];
// String s = fis.read(bytes);
// System.out.println(s);
// 通过循环读取
byte[] bytes = new byte[1024];
int n = 0;
while ((n = fis.read(bytes)) != -1) {
String s = new String(bytes, 0, n);
System.out.println(f.getName() + "文件的内容是:" + s);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} else if (f.isDirectory()) {// 如果是文件夹,其实可以不要判断,这里为了显示更清楚
// 显示文件夹下的所有文件和文件夹
// String [] fs = f.list();//返回文件的名称列表
File[] files = f.listFiles();
for (File ff : files) {
System.out.println(ff);// 默认打印文件全路径
}
}
} else {// 不存在
// 新建
try {
f.createNewFile();// 创建一个相应文件
// 并在文件中写入一些信息
FileOutputStream fos = null;
try {
fos = new FileOutputStream(f);
String s = "我是中国人\r\n";// "\n"表示换行,"\r"表示回车
String ss = "我叫钟志钢";
fos.write(s.getBytes());
fos.write(ss.getBytes());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
fos.close();// 一定要记得关闭流
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
f.mkdir();// 歌者创建一个文件夹
}
二,RandomAccessFile
完成随机读取功能,可读取指定位置的内容,文件中的所有内容都是按照字节存放的,都有固定的位置
RandomaccessFile(File f , String mode) mode:
r : 只读
w : 只写
rw : 读写模式,如果文件不存在,会自动创建
File f = new File("e:" + File.separator + "RandomAccessFile");
RandomAccessFile raf = null;
String name = null;
int age = 0;
String myname = null;
int myage = 0;
try {
raf = new RandomAccessFile(f, "rw");
name = "zhangsan";
age = 10;
raf.writeBytes(name);// 写入8字节
raf.writeInt(age);// 写入4个字节
name = "lishi ";
age = 20;
raf.writeBytes(name);// 写入8字节
raf.writeInt(age);// 写入4个字节
name = "wangwu ";
age = 28;
raf.writeBytes(name);// 写入8字节
raf.writeInt(age);// 写入4个字节
raf.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
raf = new RandomAccessFile(f, "r");// 只读的方式打开文件
byte[] b = new byte[8];// 创建byte数组
raf.skipBytes(12);// 路过12字符,读第二个
for (int i = 0; i < b.length; i++) {
b[i] = raf.readByte();// 一个一个字节读出来
}
myname = new String(b);
myage = raf.readInt();// 读取年龄
System.out.println("我的年龄是:" + myage + ",我的姓名是:" + myname);
raf.seek(0);// 回到开头,读第一个
for (int i = 0; i < b.length; i++) {
b[i] = raf.readByte();// 一个一个字节读出来
}
myname = new String(b);
myage = raf.readInt();// 读取年龄
System.out.println("我的年龄是:" + myage + ",我的姓名是:" + myname);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
这样操作很麻烦,所以java有专门的管理方法:字节流与字符流:
三, 字节与字符流(OutputStream,InputStream, Reader,Writer四个抽象类)
操作步骤:
1,使用Files类打开文件
2,通过字节流或字符流的子类,指定输出位置
3,进行读写操作
4,关闭输入/输出(资源操作最后必须关闭,否则可能出现未知错误)
1,字节流: public abstract class OutputStream extends Object implements Clonseable, Fluashable
Clonseable 表示可以关闭的操作,因为程序运行到最后肯定要关闭(close())
Fluashable 表示刷新,清空内在中的数据(flush())
OutputStrem:
File f = new File("f:" + File.separator + "test.txt");
OutputStream os = null;
try {
os = new FileOutputStream (f);//向上转型,如果文件不存在,会自动创建,如果存在,会覆盖
String s = "I am Chinese";
byte [] b = s.getBytes();//转化
try {
os.write(b);//会把之前的删除
int a = 3;
os.write(a);
os.write(b, 5, 7);//从第4个字符开始,一共7个字符,可以取到Chinese
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {//在最后关闭,不管是否出现异常,都会执行
try {
if(os != null){
os.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//如果要想保留之前的内容
try {
os = new FileOutputStream(f,true);//表示在文件后面追加内容
try {
os.write("\r\n我叫钟志钢".getBytes());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {//在最后关闭,不管是否出现异常,都会执行
try {
if(os != null){
os.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
InputStream:
File f = new File("f:" + File.separator + "test.txt");
InputStream is = null;
try {
is = new FileInputStream (f);
byte b [] = new byte[1024];//定义一个1024个字节的数据
try {
// is.read(b);//把所有内容都读取到b中(最大是1024),如果不确定文件的大小,可以利用如下方法:
// int len = is.available();//也可以用: int len = f.lenght;
// byte[] b2 = new byte[len];
// is.read(b2);
//或者从读取的数据时定义大小
// int lens = is.read(b);
// String s = new String(b, 0, lens);
//is.read();//一个一个读取
// for(int i = 0; i < b.length; i ++){
// b[i] = (byte) is.read();
// //当读到末尾时,就会出现b[i] = -1
// }
// System.out.println("is.read()"+new String(b));
//以上方法的改进
int len = 0;
int lend = 0;//读到的数据
while((lend = is.read()) != -1){
b[len] = (byte) lend;
len++;
System.out.println(lend);
}
System.out.println("输入流的数据:" + new String(b));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if(is != null){
try {
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
2, 字符流可以直接操作字符串,无需转化
Reader,FileReader其实在操作上与字节流很相似:
File f = new File("f:" + File.separator + "test.txt");
Reader is = null;
try {
is = new FileReader (f);
char b [] = new char[1024];//定义一个1024个字节的数据
try {
int len = 0;
int lend = 0;//读到的数据
while((lend = is.read()) != -1){
b[len] = (char) lend;//其实是把ASC码强力转成字符串
len++;
System.out.println(lend);
}
System.out.println("输入流的数据:" + new String(b));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if(is != null){
try {
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Writer,FileWriter,
File f = new File("f:" + File.separator + "test.txt");
Writer os = null;
try {
os = new FileWriter (f, true);//向上转型,如果文件不存在,会自动创建,如果存在,会覆盖
String s = "I am Chinese";
try {
os.write(s);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {//在最后关闭,不管是否出现异常,都会执行
try {
if(os != null){
os.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
虽然看起来很多相似的地方,但是还是有些区别:
字节流直接操作文件,字符流需要通过缓存才能操作,也就是说在字节操作中,
即使没有关闭,也会执行操作,在字符操作中,没有关闭之前,数据存在内存(缓存)中,是不会执行输出操作的
硬盘上存储的数据都是字节形式的,字符只存在于内在中.
操作实例:Copy 源文件 目标文件
String args1 [] = new String[]{
"f:" + File.separator + "test.txt",
"f:" + File.separator + "test2.txt"
};
if(args1.length!=2){ // 判断是否是两个参数
System.out.println("输入的参数不正确。") ;
System.out.println("例:java Copy 源文件路径 目标文件路径") ;
System.exit(1) ; // 系统退出
}
File f1 = new File(args1[0]) ; // 源文件的File对象
File f2 = new File(args1[1]) ; // 目标文件的File对象
if(!f1.exists()){
System.out.println("源文件不存在!") ;
System.exit(1) ;
}
InputStream input = null ; // 准备好输入流对象,读取源文件
OutputStream out = null ; // 准备好输出流对象,写入目标文件
try{
input = new FileInputStream(f1) ;
}catch(FileNotFoundException e){
e.printStackTrace() ;
}
try{
out = new FileOutputStream(f2) ;
}catch(FileNotFoundException e){
e.printStackTrace() ;
}
if(input!=null && out!=null){ // 判断输入或输出是否准备好
int temp = 0 ;
try{
while((temp=input.read())!=-1){ // 开始拷贝
out.write(temp) ; // 边读边写,最好是使用这种方式,因为如果文件过大,可能内在不够用
}
System.out.println("拷贝完成!") ;
}catch(IOException e){
e.printStackTrace() ;
System.out.println("拷贝失败!") ;
}
try{
input.close() ; // 关闭
out.close() ; // 关闭
}catch(IOException e){
e.printStackTrace() ;
}
}
四, 字节流与字符流的转换流:OutputStreamWriter,将输出的字符流转换成输出的字节流
InputStreamReader,将输入的字节流转换成输入的字符流
其实就是说字符便于在内在中操作,字节便于在硬盘中存储,在使用时进行相应的转换
OutputStreamWriter:
File f = new File("d:" + File.separator + "test.txt") ;
Writer out = null ; // 字符输出流
out = new OutputStreamWriter(new FileOutputStream(f)) ; // 字节流变为字符流
out.write("hello world!!") ; // 使用字符流输出
out.close() ;
InputStreamReader
File f = new File("d:" + File.separator + "test.txt") ;
Reader reader = null ;
reader = new InputStreamReader(new FileInputStream(f)) ; // 将字节流变为字符流
char c[] = new char[1024] ;
int len = reader.read(c) ; // 读取
reader.close() ; // 关闭
System.out.println(new String(c,0,len)) ;
五, 内在操作流:ByteArrayInputStream, ByteArrayOutputStream, 主要是程序内容与内存的交换,所以操作对象是以内在为准的,
String str = "HELLOWORLD" ; // 定义一个字符串,全部由大写字母组成
ByteArrayInputStream bis = null ; // 内存输入流
ByteArrayOutputStream bos = null ; // 内存输出流
bis = new ByteArrayInputStream(str.getBytes()) ; // 向内存中输出内容
bos = new ByteArrayOutputStream() ; // 准备从内存ByteArrayInputStream中读取内容
int temp = 0 ;
while((temp=bis.read())!=-1){
char c = (char) temp ; // 读取的数字变为字符
bos.write(Character.toLowerCase(c)) ; // 将字符变为小写
}
// 所有的数据就全部都在ByteArrayOutputStream中
String newStr = bos.toString() ; // 取出内容
try{
bis.close() ;
bos.close() ;
}catch(IOException e){
e.printStackTrace() ;
}
System.out.println(newStr) ;
六, 管道流: PipedOutputStream ,PipedInputStream 不同线程中的IO操作,从一个线程传入到另一个线程,同时进行
class Send implements Runnable{ // 线程类
private PipedOutputStream pos = null ; // 管道输出流
public Send(){
this.pos = new PipedOutputStream() ; // 实例化输出流
}
public void run(){
String str = "Hello World!!!" ; // 要输出的内容
try{
this.pos.write(str.getBytes()) ;
}catch(IOException e){
e.printStackTrace() ;
}
try{
this.pos.close() ;
}catch(IOException e){
e.printStackTrace() ;
}
}
public PipedOutputStream getPos(){ // 得到此线程的管道输出流
return this.pos ;
}
};
class Receive implements Runnable{
private PipedInputStream pis = null ; // 管道输入流
public Receive(){
this.pis = new PipedInputStream() ; // 实例化输入流
}
public void run(){
byte b[] = new byte[1024] ; // 接收内容
int len = 0 ;
try{
len = this.pis.read(b) ; // 读取内容
}catch(IOException e){
e.printStackTrace() ;
}
try{
this.pis.close() ; // 关闭
}catch(IOException e){
e.printStackTrace() ;
}
System.out.println("接收的内容为:" + new String(b,0,len)) ;
}
public PipedInputStream getPis(){
return this.pis ;
}
};
public class PipedDemo{//对接
public static void main(String args[]){
Send s = new Send() ;
Receive r = new Receive() ;
try{
s.getPos().connect(r.getPis()) ; // 连接管道
}catch(IOException e){
e.printStackTrace() ;
}
new Thread(s).start() ; // 启动线程
new Thread(r).start() ; // 启动线程
}
};
七, 打印流: PrintWriter(字符), PrintStream(字节)
PrientSteam (OutputSteam out) 属于装饰设计模式,即好看又方便
PrintStream ps = null ; // 声明打印流对象
// 如果现在是使用FileOuputStream实例化,意味着所有的输出是向文件之中
ps = new PrintStream(new FileOutputStream(new File("f:" + File.separator + "test.txt"))) ;
String name = "钟志钢" ; // 定义字符串
int age = 26 ; // 定义整数
float score = 990.356f ; // 定义小数
char sex = 'M' ; // 定义字符
//%s 表示String , %d 表示int , %f 表示小数, %c 表示字符,其实都可以用s,因为所有都可以向String转
ps.printf("姓名:%s;年龄:%s;成绩:%s;性别:%s",name,age,score,sex) ;
ps.close() ;
以前内容的文件内容结果: 姓名:钟志钢;年龄:26;成绩:990.356;性别:M
八, BufferedReader , buffer缓冲区,
接收键盘接收的数据:
BufferedReader buf = null ; // 声明对象
buf = new BufferedReader(new InputStreamReader(System.in)) ; // 将字节流变为字符流
String str = null ; // 接收输入内容
System.out.print("请输入内容:然后回车") ;
try{
str = buf.readLine() ; // 读取一行数据,输入没有最长限制,以分割符(通常是回车)为界
}catch(IOException e){
e.printStackTrace() ; // 输出信息
}
System.out.println("输入的内容为:" + str) ;
九, 全并流: SequenceInputStream , 即把各种流进行合并,
InputStream is1 = null ; // 输入流1
InputStream is2 = null ; // 输入流1
OutputStream os = null ; // 输出流
SequenceInputStream sis = null ; // 合并流
is1 = new FileInputStream("d:" + File.separator + "a.txt") ;
is2 = new FileInputStream("d:" + File.separator + "b.txt") ;
os = new FileOutputStream("d:" + File.separator + "ab.txt") ;
sis = new SequenceInputStream(is1,is2) ; // 实例化合并流
int temp = 0 ; // 接收内容
while((temp=sis.read())!=-1){ // 循环输出
os.write(temp) ; // 保存内容
}
sis.close() ; // 关闭合并流
is1.close() ; // 关闭输入流1`
is2.close() ; // 关闭输入流2
os.close() ; // 关闭输出流
十, 对象序列化, ObjectOutputStream, 对象序列化 ObjectInputStream, 对象反序列化
说的明白一点,当我们写了一个对象(例如类Person),需要存储时,就必须转换成二进制,这个过程就是序列化的过程
要被序列化的对象必须要实现接口Serializable,表示这个对象可以被序列化
先定义一个类:personprivate String name ; // 声明name属性,但是此属性不被序列化
public class Person implements Serializable{
private String name ; // 声明name属性,但是此属性不被序列化
private int age ; // 声明age属性
public Person(String name,int age){ // 通过构造设置内容
this.name = name ;
this.age = age ;
}
public String toString(){ // 覆写toString()方法
return "姓名:" + this.name + ";年龄:" + this.age ;
}
};
序列化过程:
public static void main(String args[]) throws Exception{
Person per[] = {new Person("张三",30),new Person("李四",31),
new Person("王五",32)} ;
ser(per) ;
Object o[] = (Object[])dser() ;
for(int i=0;i<o.length;i++){
Person p = (Person)o[i] ;
System.out.println(p) ;
}
}
public static void ser(Object obj[]) throws Exception {
File f = new File("D:" + File.separator + "test.txt") ; // 定义保存路径
ObjectOutputStream oos = null ; // 声明对象输出流
OutputStream out = new FileOutputStream(f) ; // 文件输出流
oos = new ObjectOutputStream(out) ;
oos.writeObject(obj) ; // 保存对象
oos.close() ; // 关闭
}
public static Object[] dser() throws Exception {
File f = new File("D:" + File.separator + "test.txt") ; // 定义保存路径
ObjectInputStream ois = null ; // 声明对象输入流
InputStream input = new FileInputStream(f) ; // 文件输入流
ois = new ObjectInputStream(input) ; // 实例化对象输入流
Object obj[] = (Object[])ois.readObject() ; // 读取对象
ois.close() ; // 关闭
return obj ;
}
十一, 字符编码 :乱码产生的原因就是所用编码不一到的原因
分类:iso8859-1,属于单字节编码,最多只能表示0-225字符范围,一般用在英文上
GBK/GB2312: 中文国际编码,专门用来表示汉字, 是双字节编码
udicode:java中使用的编码,最标准的一种,用16进制表示,但不兼容iso8859-1
UTF: 兼容iso8859-1,也可以表示所有的语言字符,但长度1-6个字节不等,中文常使用的编码
System.out.println("系统默认编码:" +
System.getProperty("file.encoding")) ; // 获取当前系统编码
File f = new File("f:" + File.separator + "test.txt") ; // 实例化File类
OutputStream out = new FileOutputStream(f) ; // 实例化输出流
byte b[] = "中国,你好!".getBytes("ISO8859-1") ; // 转码操作
out.write(b) ; // 保存
out.close() ; // 关闭
本文章相关源代码:
http://download.csdn.net/detail/zxjzzg/5170491