流(Stream)是字节的源或目的。
InputStream 和 OutputStream 是两个 abstact 类,对于字节为导向的 stream 都扩展这两个基类。
初学的时候,就记住一句话,只要带Reader或者Writer的就是字符流,带Stream就是字节流。
流的本质是用于文件本地的操作,由于网络需求,现在经常用于网络编程。所以我们还是先来看看文件之间的IO操作吧。
下面为包含了IO流的常用案例:
public class FileCreate {
public static void main(String[] args){
//在不同环境下的\分隔符是不同的,所以推荐使用File的变量
File file = new File("f:"+File.separator+"newFile.zip");
File file1 = new File("f:"+File.separator+"wenjianjia");
//创建一个文件夹
//mkdir 必须上级目录存在 才可以完成创建
//makdirs 创建所有目录文件夹
file1.mkdir();
File file2 = new File("f:"+File.separator+"ai"+File.separator);
//判断指定目录是否存在
Boolean = file2.isDrectory();
if(!file.exists()){ //如果文件不存在
try {
//创建一个该路径下的文件
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}else{
//第一次运行创建 第二次就直接delete
//如果存在就删除
file.delete();
}
}
}
public class FileIO{
public static void main(String[] args){
//在不同环境下的\分隔符是不同的,所以推荐使用File的变量
File file = new File("f://newFile.txt");
if(!file.exists()){
try {
file.createNewFile();
String str = "新年快乐";
byte[] b = str.getBytes();
OutputStream os = new FileOutputStream(file);
os.write(b, 0, b.length);
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}else{
//追加内容
try {
//第二个参数如果为true则 追加内容
//OutputStream os = new FileOutputStream(file, true);
//os.write("哈哈哈哈".getBytes());
InputStream is = new FileInputStream(file);
byte[] b = new byte[(int)file.lenth()];
//read 方法是一个字节一个字节地读 当文件读到末尾会返回-1 正常情况不会
while((is.read(b)!=-1){
}
is.close();
system.out.print(new String(b);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public class FileWR{
public static void main(String[] args) throws Exception{
File file = new File("f:\\1.txt");
if(!file.exists()){
file.createNewFile();
}
//先读出来 然后再写入另一个文件
Reader reader = new FileReader(file);
char[] ch=new char[(int) file.length()];
int len = reader.read(ch);
System.out.println(new String(ch,0,len));
File file1 = new File("f:\\2.txt");
if(!file.exists()){
file.createNewFile();
}
Writer writer = new FileWriter(file1);
writer.write(new String(ch,0,len));
reader.close();
writer.close();
}
}
注意:在我学的时候经常混淆的东西,字符流和字节流的read方法:
is.read(): 返回的是否到达末尾,是return -1,在没有return -1的情况下,它是一个字节;
reader.read(): 如上,在没有return -1的情况下,它是一个字符;
is.read(byte): 返回的是读取到的总字节数;
reader.read(char): 返回的是读取到的总字符数;
OutputStreramWriter 和InputStreamReader类
在网络操作中,我们经常从服务器获取的是字节流,所以我们在给用户看的时候,必须要将之转换为字符流。
整个IO类中除了字节流和字符流还包括字节和字符转换流。
OutputStreramWriter将输出的字符流转化为字节流
InputStreamReader将输入的字节流转换为字符流
但是不管如何操作,最后都是以字节的形式保存在文件中的。
class hello{
public static void main(String[] args) throws IOException {
String fileName= "d:"+File.separator+"hello.txt";
File file=new File(fileName);
Writer out=new OutputStreamWriter(new FileOutputStream(file));
out.write("hello");
out.close();
}
}
运行结果:
在d盘目录下,存放的hello.txt中显示hello。
class hello{
public static void main(String[] args) throws IOException {
String fileName= "d:"+File.separator+"hello.txt";
File file=new File(fileName);
Writer out=new OutputStreamWriter(new FileOutputStream(file)); //OutputStreamWriter将字节输入流转换为字符输入流
char[] b=new char[100];
int len=read.read(b); //将读取的字符存放入char中,len返回的是读取字符的总个数
System.out.println(new String(b,0,len)); //将char数组转换为String显示
read.close();
}
}
class ByteArrayIODemo{
public static void main(String[] args){
String str = "hello";
ByteArrayInputStream is = new ByteArrayInputStream(str.getBytes()); //使用str.getBytes()作为流输入的来源(数据源) 该缓冲区包含从流中读取到的字节
ByteArrayOutputStream os = new ByteArrayOutputStream(); //将字节数据当做流输出目的地
int len = 0 ;
while ((len = is.read())!=-1){
os.write(len);
}
//调用方法toString() 可以指定转换字符集编码
system.out.print(os.toString());
}
}
想对应的还有CharArrayReader和CharArrayWriter字符的操作。
//输出流
public class Out {
PipedOutputStream outputStream = null;
public Out(){
this.outputStream = new PipedOutputStream();
}
public PipedOutputStream getOut(){
return this.outputStream;
}
class myRun implements Runnable{
@Override
public void run() {
String str = "你应该可以收到的";
try {
outputStream.write(str.getBytes());
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//输入流
public class Inp {
PipedInputStream InputStream = null;
public Inp(){
this.InputStream = new PipedInputStream();
}
public PipedInputStream getInput(){
return this.InputStream;
}
class myRun implements Runnable{
@Override
public void run() {
try {
byte[] b = new byte[1024];
int len = 0 ;
len = InputStream.read(b);
System.out.println(new String(b,0,len));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//测试类
public class FileIo {
public static void main(String[] args) throws Exception{
Out out = new Out();
//得到管道输出流对象
PipedOutputStream os = out.getOut();
Inp in = new Inp();
//得到管道流输入流对象
PipedInputStream is = in.getInput();
//管道连接
os.connect(is);
//开始发送
out.new myRun().run();
//接受
in.new myRun().run();
}
}
public class SytemDemo{
public static void main(String[] args)throws Exception{
//输出到控制台
System.out.print("Hello");
//设置输出流
System.setOut(new PrintStream(new FileOutputStream(new File("f:\\hello.txt"))));
//输出到了文件当中 控制台只显示上面的输出语句
System.out.print("hello");
}
}
public class SytemDemo{
public static void main(String[] args){
//从控制台键盘读取
int len = 0 ;
byte[] b = new byte[1024];
//从键盘读取
len = System.in.read(b);
System.out.print("从键盘读到的"+new String(b,0,len));
//文件字节输入流对象
InputStream is = new FileInputStream(new File("f:\\hello"));
//设置键盘输入流 定向为文件输入流
System.setIn(is);
byte[] b = new byte[1024];
int len = 0 ;
len = System.in.read(b);
//从文件中读取打印到控制台
System.out.print(new String(b,0,len));
}
}
public void BufferedReaderDeno{
public static void main(String[] args){
//BufferedReader只接受字符缓字符流缓冲区 所以要将字节流转换为字符流
BufferedReader bf = new BufferedReader(new InputStreamReader(new FileInputStream(new File("F:\\BufferedReaderDeno"))));
//从字符缓冲区里读取一行 它是以'/r'或'\n'为分隔的
System.out.print(bf.readLine());
}
}
public void BufferedReaderDeno{
public static void main(String[] args){
BufferedWriter bf = new BufferedWriter(new OutputStreamReader(new FileOutputStream(new File("F:\\BufferedWriterDeno"))));
bf.write("i like code");
//字符其实先写到内存当中 在写入硬盘
//如果字符流不close的话 会发现文件中没有内容 可以flush
bf.close();
}
}
public class ScannerDemo{
public static void main(String[] args){
//new Scanner(arg0) arg0: 可以是字节输入流、字符输入流。都可以
Scanner scanner = new Scanner(System.in);
//自动转换 直接获得int控制台输入的int型数值
System.out.print(scanner.nextInt());
//文件一般都不需要指定 字符流还是字节流 直接一个File 对象扔进去,Scanner对象的next方法直接返回的是String类型
Scanner scanner = new Scanner(new File("F:\\Scanner.txt"));
System.out.print(scanner.next());
}
}
public class DataStreamDemo{
public static void main(String[] args){
int[] a = {1,2,3};
DataOutputStream dos = new DataOutputStream(new FileInputStream("F:\\ds.txt"));
foreach(int b : a){
dos.write(b);
}
dos.close();
DataInputStream dis = new DataInputStream(new FileInputStream("F:\\ds.txt"));
int temp = 0;
//直到存放的类型 每次取出来一个 通过方法直接拿 就行了
while((temp=dis.readInt())!=-1){
System.out.print(temp);
}
}
}
public class FileIo {
public static void main(String[] args) throws IOException{
InputStream isr1 = new FileInputStream("F:\\1.txt");
InputStream isr2 = new FileInputStream(new File("F:\\2.txt"));
//合并两个字节输入流
SequenceInputStream sq = new SequenceInputStream(isr1, isr2);
byte[] b =new byte[1024];
int len= 0;
FileOutputStream osw = new FileOutputStream("F:\\total.txt");
while ((len = sq.read(b))!=-1){
//将两个文件的内容输出在total中
osw.write(b,0,len);
}
isr1.close();
isr2.close();
sq.close();
osw.close();
}
}
public class ZipOutDemo {
public static void main(String[] args) throws IOException{
InputStream isr1 = new FileInputStream("F:\\1.txt");
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream("F:\\2.zip"));
//开始写入新的 ZIP 文件条目并将流定位到条目数据的开始处 设置第一个条目的名字
zos.putNextEntry(new ZipEntry("哈哈.txt"));
//设置zip包的注释
zos.setComment("h");
byte[] b =new byte[1024];
int len= 0;
while ((len = isr1.read(b))!=-1){
zos.write(b,0,len);
}
isr1.close();
zos.close();
}
}
public class ZipInputDemo{
public static void main(String[] args){
InputStream is = null;
OutputStream os = null;
Entry e = null;
String zipName = "javaCode.zip";
//要结果的zip文件对象
File file = new File("F:\\"+zipNmae);
//通过指定Entry条目对象,获得此条目输出流
ZipFile zip = new ZipFile(file);
//zip输入流 可以拿到Entry条目对象
ZipInputStream zis = new ZipInputStream(new FileInputStream(file));
while((e=zis.getNextEntry())!=null){
//在JAVA中"\"属于转移符号,split通过正则表达式的方式分割,在正则表达式中"\","."也属于转义符
//Java先把"\\"转换为了"\",然后正则表达式将"\."转换为了"."
File outFile = new File("F:\\"+ZipName.split("\\.")[0]+"\\"+e.getNmae());
//目录是否存在
if(!outFile.getParentFile().exists()){
//makdir 只创建一级目录,也就是如果前面目录都存在 才创建最后一个目录
//makdirs 创建所有目录
outFile.makdirs();
}
//如果文件不存在
if(!outFile.exists()){
outFile.reateNewFile();
}
is = zip.getInputStream(e);
os = new FileOutStream(outFile);
int temp = 0;
while((len = is.read())!=-1){
os.write(temp);
}
is.close();
os.close();
}
zis.close();
}
}
public class PushBackInputStreamDemo{
public static void main(String[] args){
String str = "hei.ma";
ByteArrayInputStream bs = new ByteArrayInputStream(str.getBytes());
PushbackInputStream ps = new PushbackInputStream(bs);
int len = 0 ;
while((len = ps.read())!=-1){
System.out.println("正常读:"+(char)len);
//将这个字节回退到缓冲区中
if(len =='.'){
ps.unread(len);
//先读缓冲区中被退回的字节
int a = ps.read();
System.out.println((char)a);
}
}
}
}
控制台输出:
正常读:h
正常读:e
正常读:i
正常读:.
回退: .
正常读:m
正常读:a
class person implements Serializable{
//本来是序列化全部属性 关键字tantsient可以说明 不被序列化保存
private trantsient String sex;
private String name ;
private String age;
public person(String name,String age,String sex){
this.name = name;
this.age = age;
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public String toString() {
return name+","+age;
}
public void setSex(String sex){
this.sex = sex;
}
public String getSex(){
return this.sex;
}
}
public class SerializableDemo{
public static void main(String[] args){
person s1 = new person("小明","1岁");
person s2 = new person("小红","2岁");
person p = {s1,s2};
ObjectOutputStream obo = new ObjectOutputStream(new FileOutputStream(new File("F:\\SerializableDemo.txt")));
//将两个对象序列化
obo.write(p);
ObjectInputStream obi = new ObjectInputStream(new FileInputStream(new File("F:\\SerializableDemo.txt")));
Object[] o1 = (Object[])obi.readObject();
//在文件中看到的是 乱码,因为是二进制文件,输出控制台 是可以看到的。
system.out.print(o1[0].toString()+"\n"+o1[1].toString());
}
}
输出结果:
小明,1岁
小红,2岁
class person implements Externalizable{
private String sex;
private String name ;
private String age;
public person(String name,String age,String sex){
this.name = name;
this.age = age;
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public String toString() {
return name+","+age;
}
public void setSex(String sex){
this.sex = sex;
}
public String getSex(){
return this.sex;
}
//序列化时调用(就是说 你要序列化对象的哪些属性)
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(this.name);
out.writeObject(this.age);
}
//反序列化(根据需要读取反序列化内容)
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.name = (String) in.readObject();
this.age = (String) in.readObject();
}
}
public class ExternalizableDemo{
public static void main(String[] args){
person s1 = new person("小明","1岁","男");
person s2 = new person("小红","2岁","女");
person p = {s1,s2};
ObjectOutputStream obo = new ObjectOutputStream(new FileOutputStream(new File("F:\\SerializableDemo.txt")));
//将两个对象序列化
obo.write(p);
ObjectInputStream obi = new ObjectInputStream(new FileInputStream(new File("F:\\SerializableDemo.txt")));
Object[] o1 = (Object[])obi.readObject();
system.out.print(o1[0].toString()+"\n"+o1[1].toString());
}
}
输出结果:
小明,1岁,null
小红,2岁,null
在Android中多线程下载会经常使用到RandomAccessFile随机读取文件,它可以在移动多少字节,写入。