字符编码
常见编码:
- GBK/GB2312国标,GB2312只包含简体中文,GBK有简体中文和繁体中文
- ISO8859-1,国际通用编码,可以描述所有字母信息,如果是象形文字需要经过编码处理。
- UNCODE,十六进制存储,可以描述所有文字信息
- UTF编码,象形文字采用十六进制编码,而其他文字采用ISO8859-1编码,适合用于快速传输,节约带宽。也就成为了开发首选编码。主要使用UTF-8编码
要想知道系统中支持的代码规则,则需要通过程序列出全部 属性:
列出本机属性:
package wzr.study09.io;
public class PropertyTest {
public static void main(String[] args) {
System.getProperties().list(System.out);
}
}
强制性设置编码:
import java.io.OutputStream;
import java.io.*;
public class SetcodeTest {
public static void main(String args[]) throws Exception {
File file=new File("F:\\course\\file.txt");
OutputStream out=new FileOutputStream(file,true);
out.write("\r\n强制设置编码问题\r\n".getBytes("GBK"));
out.close();
}
}
强制设置代码和资源都为UTF-8是最好的解决方式。
内存操作流
想要使用IO操作但又不想产生文件,此时解决办法为,以内存(临时文件)为终端。
使用内存需要调用的IO流与使用文件需要调用的IO流相反字节内存操作流:ByteArrayOutputStream,ByteArrayInputStream
字符内存操作流:CharArrayWriter,CharArrayReader
首先分析ByteArrayInputStream,ByteArraOutputStream构造方法:
- ByteArrayInputStream构造(将数据放到内存,然后取出):
public ByteArrayInputStream(byte[] buf)
- ByteArrayOutputStream构造(是个无参构造):
public ByteArrayOutputStream()
- ByteArrayOutputStream中有将内存流中全部的数据信息读取出来。
- 获取数据:
public byte[] toByteArray()
- 使用字符串的形式获取:
public String toString()
范例:使用内存流实现小写字母转大写字母的操作
import java.io.*;
public class MemoryIOTest {
public static void main(String[] args) throws Exception {
String str="abcdefg";
InputStream in=new ByteArrayInputStream(str.getBytes());
OutputStream out=new ByteArrayOutputStream();
int data=0;
while((data=in.read())!=-1) {
out.write(Character.toUpperCase(data));
}
System.out.println(out);
in.close();
out.close();
}
}
如果不希望以字符串的形式返回,可以使用OutputStream子类ByteArrayOutputStream的扩展功能获取全部字节数据
import java.io.*;
public class MemoryIOTest {
public static void main(String[] args) throws Exception {
String str="abcdefg";
InputStream in=new ByteArrayInputStream(str.getBytes());
//必须子类自己使用自己的扩展功能
ByteArrayOutputStream out=new ByteArrayOutputStream();
int data=0;
while((data=in.read())!=-1) {
out.write(Character.toUpperCase(data));
}
byte bt[]=out.toByteArray();
System.out.println(new String(bt));
in.close();
out.close();
}
}
管道流
实现两个线程之间IO处理,管道流也分为字节流和字符流两类。
字节管道流:PipiedOutputStream,PipedInputStream
字符管道流:PipedWriter,PipedReader
连接:
OutputStream:public void connect(PipedInputStream snk) throws IOException
Writer:public void connect(PipedReader snk) throws IOException
范例实现管道操作:
package wzr.study09.io;
import java.io.*;
public class PipelineTest {
public static void main(String[] args) throws Exception {
SendThread send=new SendThread();
ReceiveThread receive=new ReceiveThread();
send.getOutput().connect(receive.getInput());
new Thread(send,"发送消息线程").start();
new Thread(receive,"接受消息线程").start();
}
}
class SendThread implements Runnable{
private PipedOutputStream out;
public SendThread() {
out=new PipedOutputStream();
}
@Override
public void run() {
for(int i=0;i<10;i++) {
try {
out.write((Thread.currentThread().getName()+"的第"+(i+1)+"次发送!\n").getBytes());
Thread.sleep(1000);//那么依次交叉实现是线程的内容。
} catch (Exception e) {
e.printStackTrace();
}
}
//为什么要关闭?关闭了Thread就不能再次执行了
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public PipedOutputStream getOutput() {
return out;
}
}
class ReceiveThread implements Runnable{
private PipedInputStream in;
public ReceiveThread() {
in=new PipedInputStream();
}
@Override
public void run() {
byte bt[]=new byte[1024];
int len=0,num=1;
ByteArrayOutputStream bos=new ByteArrayOutputStream();
try {
//适用于收一个输出一个
while((len=in.read(bt))!=-1) {
System.out.println(Thread.currentThread().getName()+"第"+ num++ +"接收:\n"+new String(bt,0,len));
}
// 一次性全部输出
// while((len=in.read(bt))!=-1) {
// bos.write(bt,0,len);
// }
// System.out.println(Thread.currentThread().getName()+"第"+ num++ +"接收:\n"+new String(bos.toByteArray()));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public PipedInputStream getInput() {
return in;
}
}
RandomAccessFile随机存储类
对于20G的大文件,InputStream(Reader),OutputStream(Writer)很难有效实现。
RandomAccessFile可以,其可以实现文件的跳跃式读取,可以读取中间的部分内容(前提:需要有一个完善的保存形式,数据保存的位数要都确定好)。
构造方法:public RandomAccessFile(File file,String mode) throws FileNotFoundException
- 文件处理形式:r只读,rw读写
RandomAccessFile数据读取上可以跳字节读取:
- 向下跳:
public int skipBytes(int n) throws IOException
向后跳n个字节 - 自由跳:
public void seek(long pos) throws IOException
跳向pos的位置
范例:读取数据
package wzr.study09.io;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
public class RandomAccessFileTest {
public static void main(String[] args) throws Exception {
File file=new File("F:\\course\\random.txt");
if(!file.exists()) {
file.createNewFile();
}
RandomAccessFile raf=new RandomAccessFile(file,"rw");
String str[]=new String[] {"zhangsan","lisi ","wangwu "};
int ages[]=new int[] {18,25,21};
for(int i=0;i<str.length;i++) {
raf.write(str[i].getBytes());
raf.writeInt(ages[i]);
}
raf.close();
}
}
RandomAccessFile类主要作用是文件读取上。数据 长度固定,所以可以进行跳字节读取。
范例:读取数据
package wzr.study09.io;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
public class RandomAccessFileTest {
public static void main(String[] args) throws Exception {
File file=new File("F:\\course\\random.txt");
RandomAccessFile raf=new RandomAccessFile(file,"rw");
{//读取王五
raf.skipBytes(24);
byte bt[]=new byte[8];
int len=raf.read(bt);
System.out.println("名字:"+new String(bt,0,len)+",年龄:"+raf.readInt());
}
{//读取lisi
raf.seek(12);
byte bt[]=new byte[8];
int len=raf.read(bt);
System.out.println("名字:"+new String(bt,0,len)+",年龄:"+raf.readInt());
}
{//读取zhangsan
raf.seek(0);
byte bt[]=new byte[8];
int len=raf.read(bt);
System.out.println("名字:"+new String(bt,0,len)+",年龄:"+raf.readInt());
}
raf.close();
}
}
由用户自行定义读取的位置。