最近在练习的内容中,涉及了Android的文件复制,里面有关于Android输入输出流的内容,因此在网上查找了一些资料,记录在这里,方便以后查阅。
1、Android中文件读写的原理:
(1)、所有文件的储存都是字节的储存。
(2)、在磁盘上保留的并不是文件的字符而是先把字符编码成字节,再储存这些字节到磁盘。
(3)、在读取文件(特别是文本文件)时,也是一个字节一个字节的读取以形成字节序列。
2、文件读写的步骤:
(1)、首先建立通道。
(2)、然后建立数据存储空间。
(3)、然后开始读写数据。
(4)、关闭流。
3、输入流和输出流
(1)、输入流:程序从输入流读取数据源。数据源包括外界(键盘、文件、网络…),即是将数据源读入到程序的通信通道。
(2)、输出流:程序向输出流写入数据。将程序中的数据输出到外界(显示器、打印机、文件、网络…)的通信通道。
4、输入输出流类介绍
(1)、stream:是指有任何有能力产出的数据源,或是任何有能力接收数据的接收源。我们经常使用的stream基本上哦毒死从Inputstream和Outoutstream这两个类继承而来的。
(2)、stream流类型:所有的stream都包括两种类型:以字节为导向的stream和以Unicode字符为导向的stream,一般称为字节流和字符流。
字节流:以字节为单位向stream中写入或者从stream中读取。一般的二进制数据都使用字节流,比如声音和图像等。
字符流:以Unicode字符为单位向stream中写入或者从stream中读取。要处理16位的Unicode字符流就需要引进writer和reader,加入writer和reader的新的I/O类库既可以处理8位的字节流,也可以处理16位的Unicode字符流。
5、字节流和字符流的区别
(1)、字节流提了供处理任何类的I/O操作的功能,但它不能直接处理Unicode字符,字符流就可以
(2)、字节流转换成字符流可以用InputStreamReader,OutputStreamWriter。也就是上述说的引进writer和reader。
一般我们在使用的时候通常使用字节流。
6、字节流和字符流各自包含的stream类型
字节流:
input stream:
(1)、ByteArrayInputStream:把内存中的一个缓冲区作为InputStream使用
(2)、 StringBufferInputStream:把一个String对象作为InputStream
(3)、FileInputStream:把一个文件作为InputStream,实现对文件的读取操作
(4)、PipedInputStream:实现了pipe的概念,主要在线程中使用
(5)、 SequenceInputStream:把多个InputStream合并为一个InputStream
Out stream:
(1)、 ByteArrayOutputStream:把信息存入内存中的一个缓冲区中
(2)、 FileOutputStream:把信息存入文件中
(3)、 PipedOutputStream:实现了pipe的概念,主要在线程中使用
(4)、 SequenceOutputStream:把多个OutStream合并为一个OutStream
字符流:
Input Stream:
(1)、CharArrayReader:与ByteArrayInputStream对应
(2)、 StringReader:与StringBufferInputStream对应
(3)、FileReader:与FileInputStream对应
(4)、 PipedReader:与PipedInputStream对应
Out Stream:
(1)、 CharArrayWrite:与ByteArrayOutputStream对应
(2)、 StringWrite:无与之对应的以字节为导向的stream
(3)、 FileWrite:与FileOutputStream对应
(4)、 PipedWrite:与PipedOutputStream对应
7、常用的输入输出流
(1)、InputStream:产生数据的数据源,InputStream类是抽象类,不能够创建对象,需要通过子类来实现。
(2)、OutputStream:可以接收数据的数据源,和InputStream一样,也是抽象类。
(3)、FileInputStream:InoutStream类的子类,处理以文件作为输入源的数据源。常用方法:
方式1:
File file = new Fiel("d:/abc.txt");
FileInputStream in = new FileIputStream(file);
方式2:
FileInputStream in = new FileInputStream("d/abc.txt");
方式3:
构造函数将FileDescriptor()对象最为其参数
FileDescriptor() fd = new FileDescriptor();
FileInputStream in = new FileInputStream(fd);
(4)、FileOutputStream:用来处理文件作为输出的stream。常用的方法:
方式1:
File file = new Fiel("d:/abc.txt");
FileOutputStream out= new FileOutputStream(file);
方式2:
FileOutputStream out= new FileOutputStream("d/abc.txt");
方式3:
构造函数将FileDescriptor()对象最为其参数
FileDescriptor() fd = new FileDescriptor();
FileOutputStream out = new FileOutputStream(fd);
方式4:
构造函数将文件名作为其第一参数,将布尔值作为第二参数
FileOutpuStream out = new FileOutputStream("d:/abc.txt",true);
(5)、BufferedInputStream,BufferedOutputStream:允许程序在不降低系统性能的情况下一次一个字节的从流中读取或者写入数据
BufferInputstream定义了两种构造函数
(1) BufferInputStream buffer= new BufferInputstream(in);
(2) BufferInputStream buffer=new BufferInputStream(in,size)
第二个参数表示指定缓冲器的大小。
同样BufferOutputStream也有两种构造函数。一次一个字节的向流中写数据。
下面举一个简单的输入输出流的例子,使用到了FileInputStream和FileOUtputStream,就是文件的复制。
这个例子主要实现的是在文件夹下复制一张图片并保存在该文件夹中,复制的文件更换名字保存
activity_copypicture.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/btn_copy"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="复制图片"
android:layout_marginTop="10dp"/>
</LinearLayout>
CopyPictureActivity.java:
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Created by Administrator on 2017/6/18.
*/
public class CopyPictureActivity extends Activity {
private static final String TAG = "CopyPicture";
Button btnCopy;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_picturehecheng);
btnCopy = (Button)findViewById(R.id.btn_copy);
btnCopy.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
CopyPicture();
}
});
}
private void CopyPicture() {
//创建文件夹,Environment.getExternalStorageDirectory().getPath()获取根目录,如果文件夹有则不创建,没有,则创建
String pictureFilePath = Environment.getExternalStorageDirectory().getPath() + "/CopyPicture/Picture";
Log.e(TAG, "pictureFilePath=" + pictureFilePath);
File pictureFile = new File(pictureFilePath);
if (!pictureFile.exists()) {
try {
pictureFile.mkdirs();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (pictureFile.exists()) {
Log.e(TAG, "pictureFile创建成功");
} else {
Log.e(TAG, "pictureFile创建失败");
}
}
} else {
Log.e(TAG, "pictureFile存在,地址=" + pictureFilePath);
}
String inFile = pictureFilePath + "/源图片名.jpg";
InputStream in = null;
OutputStream out = null;
try {
File outFile = new File(pictureFilePath + "/复制后图片名.jpg");
if (outFile.exists()){
Log.e(TAG,"outFile已经存在");
}else {
if (outFile.createNewFile()){
Log.e(TAG,"创建文件" + outFile.getPath() + "成功");
}else {
Log.e(TAG,"创建文件" + outFile.getPath() + "失败");
}
}
in = new FileInputStream(inFile);
out = new FileOutputStream(outFile);
byte[] buffer = new byte[1024]; //创建字节数组
int read;
while ((read = in.read(buffer)) != -1){ //循环读取数据并且将数据写入到缓存输出流中
out.write(buffer, 0, read);
out.flush();
}
}catch (IOException e){
e.printStackTrace();
}finally {
if (in != null){
try {
in.close(); //关闭输入流
}catch (IOException e){
//NOOP
}
}
if (out != null){
try {
out.close(); //关闭输出流
}catch (IOException e){
//NOOP
}
}
}
}
}
最后的结果就是在Picture文件夹下有两张不同名字的相同样子的图片