Java IO Basic
- 首先看下关于Java的IO的图: 我看到这个,感觉头都大了不少。Java的先驱们简直是煞费苦心,来设计Java IO。
- 字节流
import java.io.File;
/**
* Created by XYD on 2016/1/4 0004.
*/
public class FileExample {
public static void main(String[] args){
FileExample example = new FileExample();
example.createFile();
}
private void createFile(){
File f = new File("F:\\f\\2365157.lrc");
try {
f.createNewFile();//当文件不存在时,创建文件
System.out.println("该分区大小"+f.getTotalSpace()/(**)+"G");
f.mkdirs();//创建指定目录,所有必须但不存在的父目录
System.out.println("文件名 "+f.getName());
System.out.println("文件父目录字符串"+f.getParent());
}catch (Exception e){
e.printStackTrace();
}
}
}
2.InputStream
import java.io.*;
/**
* Created by XYD on 2016/1/4 0004.
* 检测文件的长度
*/
public class FileLength {
public static void main(String[] args){
int count=;//统计文件字节长度
InputStream stream=null;//文件输入流
try {
stream = new FileInputStream(new File("F:\\f\\2365157.lrc"));
//FileInputStream是有缓冲区的,所以用完之后必须关闭,否则可能导致内存占满,数据丢失。
while (stream.read()!=-){//读取文件字节,并递增指针到下一个字节
count++;
}
System.out.println("---长度是: "+count+" 字节");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
finally {
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
上面的程序肯定是有问题的,每读一个字节都要用到FileInputStream,如果是300字节,使用300次;如果是30000次,就要进行30000次操作.....想想都有些可怕,如果文件十分庞大的话,这样的做法会出大问题,这样就引出了缓冲区的使用。
可以使用stream.read(byte[] b)来代替stream.read(),这个方法可以一次读取字节数目等于数组长度的字节,**读取的数据存储在字节数组中,并且返回读取的字节数。**
3.FileOutputStream
以一个文件复制程序来描述下怎么使用它,同时展示下缓冲区的使用。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* Created by XYD on 2016/1/4 0004.
*/
public class FileCopy {
public static void main(String[] args){
byte[] buffer = new byte[];//缓冲区大小
int numberRead=;//一次读取的字节数
FileInputStream input = null;
FileOutputStream out = null;
try {
input=new FileInputStream("F:\\f\\2365157.lrc");
out=new FileOutputStream("F:\\f\\2365157_copy.lrc");//如果文件不存在会自动创建
while ((numberRead=input.read(buffer))!=-){//numberRead的目的在于防止最后一次读取的字节小于buffer长度
out.write(buffer,,numberRead);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
4.读写对象:ObjectInputStream 和ObjectOutputStream
该流允许读取或写入用户自定义的类,但是要实现这种功能,被读取和写入的类必须实现Serializable接口(这个接口里面什么方法都没有,但却是必不可少,奇怪!).
import java.io.*;
/**
* Created by XYD on 2016/1/4 0004.
*/
public class ObjectStream {
public static void main(String[] args){
ObjectOutputStream objectWriter =null;
ObjectInputStream objectReader=null;
try {
objectWriter = new ObjectOutputStream(new FileOutputStream("F:\\f\\2365157_copy.lrc"));
objectWriter.writeObject(new Student("gg",));
objectWriter.writeObject(new Student("tt",));
objectWriter.writeObject(new Student("zz",));
objectReader = new ObjectInputStream(new FileInputStream("F:\\f\\2365157_copy.lrc"));
for(int i=;i<;i++){
System.out.println(objectReader.readObject());
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
class Student implements Serializable{
private String name;
private int age;
public Student(String name , int age){
super();
this.name=name;
this.age=age;
}
@Override
public String toString() {
return "Student + [ name = "+name+", age = "+age+"]";
}
}
5.DataInputStream、DataOutputStream
有时没有必要存储整个对象的信息,而只是要存储一个对象的成员数据,成员数据的类型假设都是Java的基本数据类型,这样的需求不必使用到与Object输入、输出相关的流对象,可以使用DataInputStream、DataOutputStream来写入或读出数据。
/**
* Created by XYD on 2016/1/4 0004.
*/
public class Member {
private String name;
private int age;
public Member(String name, int age){
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
打算将Member类实例的成员数据写入文件中,并打算在读入文件数据后,将这些数据还原为Member对象。下面的代码简单示范了如何实现这个需求。
DataInputStream的好处在于在从文件读出数据时,不用费心地自行判断读入字符串时或读入int类型时何时将停止,使用对应的readUTF()和readInt()方法就可以正确地读入完整的类型数据。
import java.io.*;
/**
* Created by XYD on 2016/1/4 0004.
*/
public class DataStreamDemo {
public static void main(String[] args){
Member[] members = {
new Member("heheda",),
new Member("dacaibi",),
new Member("xyd",)};
try {
DataOutputStream outputStream = new DataOutputStream(new FileOutputStream("F:\\f\\2365157_copy.lrc"));
for(Member member:members){
//写入UTF字符串
outputStream.writeUTF(member.getName());
//写入int数据
outputStream.writeInt(member.getAge());
}
//所有数据至目的地(但是我测试了下,并没有什么卵用)
// outputStream.flush();
//关闭流
outputStream.close();
DataInputStream inputStream = new DataInputStream(new FileInputStream("F:\\f\\2365157_copy.lrc"));
//读出数据并还原为对象
for(int i=;i<members.length;i++){
String name=inputStream.readUTF();
int age=inputStream.readInt();
members[i] = new Member(name,age);
}
inputStream.close();
for(Member member:members){
System.out.printf("%s\t%d%n", member.getName(), member.getAge());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
6.PushbackInputStream类继承了FilterInputStream类是iputStream类的修饰者。SequenceInputStream:有些情况下,当我们需要从多个输入流中向程序读入数据。此时,可以使用合并流,将多个输入流合并成一个SequenceInputStream流对象。(没用过,不想写了)
7.PrintStream 说这个名字可能你不熟悉,如果说System.out.print()你肯定熟悉,System.out这个对象就是PrintStream;
-
字符流
1.FileReader ,PrintWriter ,BufferedWriter 和 BufferedReader
import java.io.*;
/**
* Created by XYD on 2016/1/4 0004.
*/
public class FileReaderDemo {
public static void main(String[] args){
FileReaderDemo demo = new FileReaderDemo();
//两个方法只能有一个被使用,不知道为什么,知道的大哥求指教
// demo.bufferReader();//使用BufferedWriter 和 BufferedReader
demo.fileReader();//使用FileReader和PrintWriter,这个会出现乱码
}
private void fileReader(){
char[] buffer = new char[];
int numberRead=;
FileReader reader=null;
PrintWriter writer=null;
try {
reader=new FileReader("F:\\f\\2365157.lrc");
writer=new PrintWriter(System.out);
while ((numberRead=reader.read(buffer))!=-){
writer.write(buffer,,numberRead);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
writer.close();
}
}
private void bufferReader(){
char[] buffer = new char[];
int numberRead=;
InputStreamReader reader=null;
PrintWriter writer=null;
try {
reader = new InputStreamReader(new FileInputStream("F:\\f\\2365157.lrc"),"UTF-8");
writer = new PrintWriter(System.out);
while((numberRead=reader.read(buffer))!=-){
writer.write(buffer,,numberRead);
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
finally {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
writer.close();
}
}
}
2.Console类,该类提供了用于读取密码的方法,可以禁止控制台回显并返回char数组,对两个特性对保证安全有作用,平时用的不多,了解就行
3.StreamTokenizer 类,这个类非常有用,它可以把输入流解析为标记(token), StreamTokenizer 并非派生自InputStream或者OutputStream,而是归类于io库中,因为StreamTokenizer只处理InputStream对象。
首先是文本对象:
‘水上漂’
青青草
“i love cjjjjj”
{3211}
23223 3523
i love wyh ,。
. ,
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.StreamTokenizer;
/**
* Created by XYD on 2016/1/4 0004.
*/
/**
* 使用StreamTokenizer来统计文件中的字符数
* StreamTokenizer 类获取输入流并将其分析为“标记”,允许一次读取一个标记。
* 分析过程由一个表和许多可以设置为各种状态的标志控制。
* 该流的标记生成器可以识别标识符、数字、引用的字符串和各种注释样式。
*
* 默认情况下,StreamTokenizer认为下列内容是Token: 字母、数字、除C和C++注释符号以外的其他符号。
* 如符号"/"不是Token,注释后的内容也不是,而"\"是Token。单引号和双引号以及其中的内容,只能算是一个Token。
* 统计文章字符数的程序,不是简单的统计Token数就万事大吉,因为字符数不等于Token。按照Token的规定,
* 引号中的内容就算是10页也算一个Token。如果希望引号和引号中的内容都算作Token,应该调用下面的代码:
* st.ordinaryChar('\'');
* st.ordinaryChar('\"');
*/
public class StreamTokenizerExample {
public static void main(String[] args){
String fileName = "f:\\f\\test.txt";
StreamTokenizerExample.statis(fileName);
}
public static long statis(String fileName){
FileReader reader=null;
try {
reader=new FileReader(fileName);
//创建分析给定字符流的标记生成器
StreamTokenizer st = new StreamTokenizer(reader);
//ordinaryChar方法指定字符参数在此标记生成器中是“普通”字符。
//下面指定单引号、双引号和注释符号是普通字符
st.ordinaryChar('\'');
st.ordinaryChar('\"');
st.ordinaryChar('/');
String s;
int numberSum=;
int wordSum=;
int symbolSum=;
int total=;
//nextToken方法读取下一个Token.
//TT_EOF指示已读到流末尾的常量。
while (st.nextToken()!=StreamTokenizer.TT_EOF){
//在调用 nextToken 方法之后,ttype字段将包含刚读取的标记的类型
switch (st.ttype){
//TT_EOL指示已读到行末尾的常量。
case StreamTokenizer.TT_EOL:
break;
//TT_NUMBER指示已读到一个数字标记的常量
case StreamTokenizer.TT_NUMBER:
//如果当前标记是一个数字,nval字段将包含该数字的值
s=String.valueOf(st.nval);
System.out.println("数字有:"+s);
numberSum++;
break;
//TT_WORD指示已读到一个文字标记的常量
case StreamTokenizer.TT_WORD:
//如果当前标记是一个文字标记,sval字段包含一个给出该文字标记的字符的字符串
s=st.sval;
System.out.println("单词有:"+s);
wordSum++;
break;
default:
//如果以上3中类型都不是,则为英文的标点符号
s=String.valueOf((char)st.ttype);
System.out.println("标点有: "+s);
symbolSum++;
}
}
System.out.println("数字有 "+numberSum+"个");
System.out.println("单词有 "+wordSum+"个");
System.out.println("标点符号有 "+symbolSum+"个");
total=symbolSum+numberSum+wordSum;
System.out.println("Total="+total);
return total;
} catch (FileNotFoundException e) {
e.printStackTrace();
return -;
} catch (IOException e) {
e.printStackTrace();
return -;
}
finally {
if(reader!=null){
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}