java学习笔记16--I/O流和文件
本文地址:http://www.cnblogs.com/archimedes/p/java-study-note16.html,转载请注明源地址。
IO(Input Output)流
IO流用来处理设备之间的数据传输,对数据的操作是通过流的方式,Java用于操作流的对象都在IO包中
输入/输出流可以从以下几个方面进行分类
从流的方向划分:
输入流、输出流
从流的分工划分:
节点流、处理流
从流的内容划分:
面向字符的流、面向字节的流
字符流和字节流
字符流的由来: 因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。 字节流和字符流的区别:
读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。
结论:只要是处理纯文本数据,就优先考虑使用字符流。 除此之外都使用字节流。
流按流向分为:输入流、输出流
IO流常用基类
字节流的抽象基类:
•InputStream,OutputStream。
字符流的抽象基类:
•Reader, Writer。
注:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。
如:InputStream的子类FileInputStream。
如:Reader的子类FileReader。
Java流操作有关的类或接口:
Java流类图结构:
读写文本文件
写文本文件
import java.io.*;
class Ex1{
public static void main ( String[] args ) throws IOException {
//main方法中声明抛出IO异常
String fileName = "C:\\Hello.txt";
FileWriter writer = new FileWriter( fileName );
writer.write( "Hello!\n");
writer.write( "This is my first text file,\n" );
writer.write( "You can see how this is done.\n" );
writer.write("输入一行中文也可以\n");
writer.close();
}
}
说明:
每次运行这个程序,都将删除已经存在的”Hello.txt”文件,创建一个新的同名文件。FileWriter的构造方法有五个,本例是通过一个字符串指定文件名来创建。FileWriter类的write方法向文件中写入字符
Writer类的流可实现内部格式到外部磁盘文件格式的转换
“Hello.txt”是一个普通的ASCII码文本文件,每个英文字符占一个字节,中文字符占两个字节
Java程序中的字符串则是每个字符占两个字节的,采用Unicode编码
close方法清空流里的内容并关闭它。如果不调用该方法,可能系统还没有完成所有数据的写操作,程序就结束了
在看一个例子:处理IO异常
import java.io.*;
class Ex2 {
public static void main ( String[] args ) {
String fileName = "c:\\Hello.txt" ;
try { //将所有IO操作放入try块中
FileWriter writer = new FileWriter( fileName ,true );
writer.write( "Hello!\n");
writer.write( "This is my first text file,\n" );
writer.write( "You can see how this is done. \n" );
writer.write("输入一行中文也可以\n");
writer.close();
}
catch ( IOException iox) {
System.out.println("Problem writing" + fileName ); }
}
}
说明:
运行此程序,会发现在原文件内容后面又追加了重复的内容,这就是将构造方法的第二个参数设为true的效果
如果将文件属性改为只读属性,再运行本程序,就会出现IO错误,程序将转入catch块中,给出出错信息
如果需要写入的内容很多,就应该使用更为高效的缓冲器流类BufferedWriter
FileWriter和BufferedWriter类都用于输出字符流,包含的方法几乎完全一样,但BufferedWriter多提供了一个newLine()方法用于换行
使用BufferedWriter完成上面的功能:
import java.io.*;
class Ex3 {
public static void main ( String[] args ) throws IOException {
String fileName = "C:/newHello.txt" ;
BufferedWriter out = new BufferedWriter(
new FileWriter( fileName ) );
out.write( "Hello!" );
out.newLine() ;
out.write( "This is another text file using BufferedWriter," );
out.newLine(); ;
out.write( "So I can use a common way to start a newline" );
out.close();
}
}
读文本文件
FileReader类
从文本文件中读取字符
继承自Reader抽象类的子类InputStreamReader
BufferedReader
读文本文件的缓冲器类
具有readLine()方法,可以对换行符进行鉴别,一行一行地读取输入流中的内容
继承自Reader
文件输入方法:
BufferedReader in = new BufferedReader(new FileReader( fileName) );
从Hello.txt中读取文本并显示在屏幕上
import java.io.*;
class Ex4 {
public static void main ( String[] args ) {
String fileName = "C:/Hello.txt" , line;
try {
BufferedReader in = new BufferedReader(
new FileReader( fileName ) );
line = in.readLine(); //读取一行内容
while ( line != null ) {
System.out.println( line );
line = in.readLine();
}
in.close();
}
catch ( IOException iox ) {
System.out.println("Problem reading " + fileName );
}
}
}
运行该程序,屏幕上将逐行显示出Hello.txt文件中的内容
FileReader对象:创建后将打开文件,如果文件不存在,会抛出一个IOException
BufferedReader类的readLine()方法:从一个面向字符的输入流中读取一行文本。如果其中不再有数据,返回null
Reader类的read()方法:也可用来判别文件结束。该方法返回的一个表示某个字符的int型整数,如果读到文件末尾,返回 -1。据此,可修改本例中的读文件部分:
int c;
while((c=in.read())!= -1) System.out.print((char)c);
close()方法:为了操作系统可以更为有效地利用有限的资源,应该在读取完毕后,调用该方法
指定源文件和目标文件名,将源文件的内容拷贝至目标文件。调用方式为:
java copy sourceFile destinationFile
class CopyMaker {
String sourceName, destName;
BufferedReader source;
BufferedWriter dest;
String line;
private boolean openFiles() {
try {
source = new BufferedReader(new FileReader(sourceName));
} catch (IOException ex) {
System.out.println("Problem opening " + sourceName);
return false;
}
try {
dest = new BufferedWriter(new FileWriter(destName));
} catch (IOException ex) {
System.out.println("Problem opening " + destName);
return false;
}
return true;
}
private boolean copyFiles() {
try {
line = source.readLine();
while(line != null) {
dest.write(line);
dest.newLine();
line = source.readLine();
}
} catch (IOException ex) {
System.out.println("Problem reading or writing");
return false;
}
return true;
}
private boolean closeFiles() {
boolean retVal = true;
try {
source.close();
} catch (IOException ex) {
System.out.println("Prolem closing " + sourceName);
retVal = false;
}
try {
dest.close();
} catch (IOException ex) {
System.out.println("Problem closing " + destName);
retVal = false;
}
return retVal;
}
public boolean copy(String src, String dst) {
sourceName= src;
destName = dst;
return openFiles() && copyFiles() && closeFiles();
}
} public class CopyFile {
public static void main(String[] args) {
if(args.length == 2)
new CopyMaker().copy(args[0], args[1]);
else
System.out.println("Please Enter names");
}
}
读写二进制文件
二进制文件
原则上讲,所有文件都是由8位的字节组成的
如果文件字节中的内容应被解释为字符,则文件被称为文本文件;如果被解释为其它含义,则文件被称为二进制文件
例如文字处理程序,例如字处理软件Word产生的doc文件中,数据要被解释为字体、格式、图形和其他非字符信息。因此,这样的文件是二进制文件,不能用Reader流正确读取
为什么需要二进制文件?
输入输出更快
比文本文件小很多
有些数据不容易被表示为字符
抽象类OutputStream
派生类FileOutputStream
用于一般目的输出(非字符输出)
用于成组字节输出
派生类DataOutputStream
具有写各种基本数据类型的方法
将数据写到另一个输出流
它在所有的计算机平台上使用同样的数据格式
其常用的一些方法见下表
例:将三个int型数字255/0/-1写入数据文件data1.dat
public class ext6_7 {
public static void main(String[] args) {
String fileName = "c:/data1.dat";
int value0 = 255, value1 = 0, value2 = -1;
try {
DataOutputStream out = new DataOutputStream(
new FileOutputStream(fileName));
out.writeInt(value0);
out.writeInt(value1);
out.writeInt(value2);
out.close();
} catch (IOException ex) {
System.out.println("Problem writing " + fileName);
}
}
}
说明:
FileOutputStream类的构造方法负责打开文件“data1.dat”用于写数据
FileOutputStream类的对象与DataOutputStream对象连接,写基本类型的数据
BufferedOutputStream
写二进制文件的缓冲流类
类似于文本文件中的BufferedWriter
对于大量数据的写入,可提高效率
用法示例:
DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream( fileName ) ) );
例:向文件中写入各种数据类型的数,并统计写入的字节数
public class ex6_8 {
public static void main(String[] args) throws IOException {
String fileName = "c:/mixedTypes.dat";
DataOutputStream dataOut = new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream(fileName)));
dataOut.writeInt(0);
System.out.println(dataOut.size() + "bytes have been written.");
dataOut.writeDouble(31.2);
System.out.println(dataOut.size() + "bytes have been written.");
dataOut.writeBytes("java");
System.out.println(dataOut.size() + "bytes have been written.");
dataOut.close();
}
}
读二进制文件
过滤流
读或写的同时对数据进行处理
通过另外一个流来构造一个过滤流
大部分java.io 包所提供过滤流都是FilterInputStream和FilterOutputStream的子类:
DataInputStream 和 DataOutputStream
BufferedInputStream 和 BufferedOutputStream
LineNumberInputStream
PushbackInputStream
PrintStream
读取上面的例子创建的数据文件中的3个int型数字,显示相加结果
public class ex6_10 {
public static void main(String[] args) {
String fileName = "C:\\data1.dat";
int sum = 0;
try {
DataInputStream instr = new DataInputStream(
new BufferedInputStream(new FileInputStream(fileName)));
sum += instr.readInt();
sum += instr.readInt();
sum += instr.readInt();
System.out.println("The sum is: " + sum);
instr.close();
} catch (IOException ex) {
System.out.println("Problem reading " + fileName);
}
}
}
分析:
readInt方法可以从输入流中读入4个字节并将其当作int型数据
由于知道文件中存储的是3个int型数据,所以使用了3个读入语句
如果不知道数据的个数该怎么办呢?因为DataInputStream的读入操作如遇到文件结尾就会抛出EOFException异常,所以我们可以将读操作放入try块中
将读操作放入try块中,使遇到文件结尾就会抛出EOFException异常,进入到相应的catch块中
try
{
while(true) sum += instr.readInt();
}
catch ( EOFException eof )
{
System.out.println("The sum is: " + sum);
instr.close();
}
File类
表示磁盘文件信息
定义了一些与平台无关的方法来操纵文件
–创建、删除文件
–重命名文件
–判断文件的读写权限及是否存在
–设置和查询文件的最近修改时间等
构造文件流可以使用File类的对象作为参数
File类常用方法:
例:在C盘创建文件Hello.txt,如果存在则删除旧文件,不存在则直接创建新的
public class ex6_13 {
public static void main(String[] args) {
File f = new File("C:" + File.separator + "hello.txt");
if(f.exists()) {
f.delete();
} else {
try {
f.createNewFile();
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
}
处理压缩文件
压缩流类
–java.util.zip包中提供了一些类,使我们可以以压缩格式对流进行读写
–它们都继承自字节流类OutputStream和InputStream
–其中GZIPOutputStream和ZipOutputStream可分别把数据压缩成GZIP格式和Zip格式
–GZIPInputStream和ZipInputStream可以分别把压缩成GZIP格式或Zip的数据解压缩恢复原状
public class ex6_14 {
public static void main(String[] args) throws IOException{
FileInputStream in = new FileInputStream("c:/Hello.txt");
GZIPOutputStream out = new GZIPOutputStream( //生成压缩文件test.gz
new FileOutputStream("c:/test.gz"));
System.out.println("Writing compressing file from" +
"c:/Hello.txt to c:/test.gz");
int c;
while((c = in.read()) != -1) {
out.write(c);
}
in.close();
out.close();
System.out.println("Reading file form c:/test.gz to monitor");
BufferedReader in2 = new BufferedReader(
new InputStreamReader(
new GZIPInputStream(
new FileInputStream("c:/test.gz"))));
String s;
while((s = in2.readLine()) != null) System.out.println(s);
in2.close();
System.out.println("Writing decompression to c:/newHello.txt");
GZIPInputStream in3 = new GZIPInputStream( //读取test.gz中的内容
new FileInputStream("c:/test.gz"));
FileOutputStream out2 = new FileOutputStream("c:/newHello.txt");
while((c = in3.read()) != -1) out2.write(c);
in3.close();
out2.close();
}
}
Zip文件
–可能含有多个文件,所以有多个入口(Entry)
–每个入口用一个ZipEntity对象表示,该对象的getName()方法返回文件的最初名称
ZipOutputStream
–父类是DeflaterOutputStream
–可以把数据压缩成ZIP格式
ZipInputStream
–父类是InflaterInputStream
–可以把压缩成ZIP格式的数据解压缩
例:指定若干文件名,将所有文件压缩为"c:/test.zip",再从此压缩文件中解压缩并显示
public class ex6_15 {
public static void main(String[] args) throws IOException {
ZipOutputStream out = new ZipOutputStream(
new BufferedOutputStream(
new FileOutputStream("c:/test.zip")));
String[] s = {"c:/t1.txt", "c:/t2.txt", "c:/t3.txt"}; //文件路径
for(int i = 0; i < s.length; i++) {
System.out.println("Writing file" + s[i]);
BufferedInputStream in = new BufferedInputStream(
new FileInputStream(s[i]));
out.putNextEntry(new ZipEntry(s[i]));
int c;
while((c = in.read()) != -1) out.write(c);
in.close();
}
out.close();
System.out.println("Reading file");
ZipInputStream in2 = new ZipInputStream(
new BufferedInputStream(
new FileInputStream("c:/test.zip")));
ZipEntry ze;
while((ze = in2.getNextEntry()) != null) {
System.out.println("Reading file " + ze.getName());
int x;
while((x = in2.read()) != -1) System.out.write(x);
System.out.println();
}
in2.close();
}
}
再看一个例子:解压缩Zip文件,并恢复其原来路径
class Unzip {
byte[] doc = null; ; //存储解压缩数据的缓冲字节数组
String FileName = null; //压缩文件名字符串
String UnZipPath = null; //解压缩路径字符串
public Unzip(String filename, String unZipPath) {
this.FileName = filename;
this.UnZipPath = unZipPath;
this.setUnZipPath(this.UnZipPath);
}
public Unzip(String filename) {
this.FileName = new String(filename);
this.UnZipPath = null;
this.setUnZipPath(this.UnZipPath);
}
private void setUnZipPath(String unZipPath) {
if(unZipPath.endsWith("\\"))
this.UnZipPath = new String(unZipPath);
else
this.UnZipPath = new String(unZipPath + "\\");
}
public void doUnZip() {
try {
ZipInputStream zipis = new ZipInputStream(
new FileInputStream(FileName));
ZipEntry fEntry = null;
while((fEntry = zipis.getNextEntry()) != null) {
if(fEntry.isDirectory()) {
checkFilePath(UnZipPath + fEntry.getName());
} else { //是文件则解压缩文件
String fname = new String(UnZipPath + fEntry.getName());
try {
FileOutputStream out = new FileOutputStream(fname);
doc = new byte[512];
int n;
while((n = zipis.read(doc, 0, 512)) != -1) {
out.write(doc, 0, n);
}
out.close();
out = null;
doc = null;
} catch (Exception ex) { }
}
}
zipis.close(); //关闭输入流
} catch (IOException ioe) {
System.out.println(ioe);
}
}
private void checkFilePath(String dirName) {
File dir = new File(dirName);
if(!dir.exists())
dir.mkdirs();
}
}
public class ex6_16 {
public static void main(String[] args) {
String zipFile = "c:/test.zip";
String unZipPath = "";
Unzip myZip = new Unzip(zipFile, unZipPath);
myZip.doUnZip();
}
}
对象序列化
保存对象的信息,在需要的时候,再读取这个对象
内存中的对象在程序结束时就会被垃圾回收机制清除
用于对象信息存储和读取的输入输出流类:
ObjectInputStream、ObjectOutputStream
实现对象的读写
通过ObjectOutputStream把对象写入磁盘文件
通过ObjectInputStream把对象读入程序
–不保存对象的transient和static类型的变量
–对象要想实现序列化,其所属的类必须实现Serializable接口
必须通过另一个流构造ObjectOutputStream:
FileOutputStream out = new FileOutputStream("theTime");
ObjectOutputStream s = new ObjectOutputStream(out);
s.writeObject("Today");
s.writeObject(new Date());
s.flush();
必须通过另一个流构造ObjectInputStream:
FileInputStream in = new FileInputStream("theTime");
ObjectInputStream s = new ObjectInputStream(in);
String today = (String)s.readObject();
Date date = (Date)s.readObject();
空接口,使类的对象可实现序列化
Serializable 接口的定义:
package java.io;
public interface Serializable {
// there's nothing in here!
};
实现Serializable接口的语句
public class MyClass implements Serializable {
...
}
使用关键字transient可以阻止对象的某些成员被自动写入文件
看一个例子:
创建一个书籍对象,并把它输出到一个文件book.dat中,然后再把该对象读出来,在屏幕上显示对象信息
class Book implements Serializable {
int id;
String name;
String author;
float price;
public Book(int id, String name, String author, float price) {
this.id = id;
this.name = name;
this.author = author;
this.price = price;
}
}
public class ex6_17 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Book book = new Book(100000, "java programming", "Wu", 23);
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("c:/book.dat"));
oos.writeObject(book);
oos.close();
System.out.println("ID is: " + book.id);
System.out.println("name is: " + book.name);
System.out.println("author is: " + book.author);
System.out.println("price is: " + book.price);
}
}
Externalizable 接口
–实现该接口可以控制对象的读写
–API中的说明为
public interface Externalizable extends Serializable
–其中有两个方法writeExternal()和readExternal(),因此实现该接口的类必须实现这两个方法
–ObjectOutputStream的writeObject()方法只写入对象的标识,然后调用对象所属类的writeExternal()
–ObjectInputStream的readObject()方法调用对象所属类的readExternal()
随机文件读写
RandomAccessFile类
–可跳转到文件的任意位置读/写数据
–可在随机文件中插入数据,而不破坏该文件的其他数据
–实现了DataInput 和 DataOutput 接口,可使用普通的读写方法
–有个位置指示器,指向当前读写处的位置。刚打开文件时,文件指示器指向文件的开头处。对文件指针显式操作的方法有:
int skipBytes(int n):把文件指针向前移动指定的n个字节
void seek(long):移动文件指针到指定的位置。
long getFilePointer():得到当前的文件指针。
–在等长记录格式文件的随机读取时有很大的优势,但仅限于操作文件,不能访问其它IO设备,如网络、内存映像等
public RandomAccessFile(File file,String mode) throws FileNotFoundException
public RandomAccessFile(String name, String mode) throws FileNotFoundException
new RandomAccessFile("farrago.txt", "r");
new RandomAccessFile("farrago.txt", "rw");
RandomAccessFile类常用API
例:创建一个雇员类,包括姓名、年龄。姓名不超过8个字符,年龄是int类型。每条记录固定为20个字节。使用RandomAccessFile向文件添加、修改、读取雇员信息
class Employee {
char name[] = {'\u0000', '\u0000','\u0000', '\u0000',
'\u0000', '\u0000', '\u0000', '\u0000'};
int age;
public Employee(String name, int age) throws Exception {
if(name.toCharArray().length > 8)
System.arraycopy(name.toCharArray(), 0, this.name, 0, 8);
else
System.arraycopy(name.toCharArray(), 0, this.name, 0, name.toCharArray().length);
this.age = age;
}
} public class ex6_18 {
String FileName;
public ex6_18(String FileName) {
this.FileName = FileName;
}
public void writeEmployee(Employee e, int n) throws Exception {
RandomAccessFile ra = new RandomAccessFile(FileName, "rw");
ra.seek(n * 20); //将位置指示器移到指定位置上
for(int i = 0; i < 8; i++) ra.writeChar(e.name[i]);
ra.writeInt(e.age);
ra.close();
}
public void readEmployee(int n) throws Exception {
char buf[] = new char[8];
RandomAccessFile ra = new RandomAccessFile(FileName, "r");
ra.seek(n * 20);
for(int i = 0; i < 8; i++) buf[i] = ra.readChar();
System.out.print("name: ");
System.out.println(buf);
System.out.println("age: " + ra.readInt());
ra.close();
}
public static void main(String[] args) throws Exception {
ex6_18 t = new ex6_18("c:/temp.txt");
Employee e1 = new Employee("zhangsan", 22);
Employee e2 = new Employee("lisi", 20);
Employee e3 = new Employee("wangwu", 25);
t.writeEmployee(e1, 0);
t.writeEmployee(e3, 2);
System.out.println("第1个雇员的信息");
t.readEmployee(0);
System.out.println("第3个雇员的信息");
t.readEmployee(2);
System.out.println("第2个雇员的信息");
t.readEmployee(1);
}
}
您还可能感兴趣:
java学习笔记系列:
java学习笔记16--I/O流和文件的更多相关文章
- Java学习笔记40(缓冲流)
缓冲流: 在读写文件的各种流中,最令人烦恼的就是效率问题, 而缓冲流的目的就是提高读写效率 字节输出缓冲流: package demo; import java.io.BufferedOutputSt ...
- Java分享笔记:使用缓冲流复制文件
[1] 程序设计 /*------------------------------- 1.缓冲流是一种处理流,用来加快节点流对文件操作的速度 2.BufferedInputStream:输入缓冲流 3 ...
- Java学习笔记之I/O流(读取压缩文件以及压缩文件)
1.读取压缩文件:ZipInputStream 借助ZipFile类的getInputStream方法得到压缩文件的指定项的内容,然后传递给InputStreamReader类的构造方法,返回给Buf ...
- Java学习笔记43(打印流、IO流工具类简单介绍)
打印流: 有两个类:PrintStream,PrintWriter类,两个类的方法一致,区别在于构造器 PrintStream:构造方法:接收File类型,接收字符串文件名,接收字节输出流(Outpu ...
- Java学习笔记42(序列化流)
对象中的数据,以流的形式,写入到文件中保存 过程称为写出对象,对象的序列化 ObjectOutputStream将对象写到文件中,实现序列化 在文件中,以流的形式,将对象读取出来, 读取对象,对象的反 ...
- Java学习笔记39(转换流)
转换流:字符流和字节流之间的桥梁 用于处理程序的编码问题 OutputStreamWriter类:字符转字节流 写文本文件: package demo; import java.io.FileOutp ...
- Java学习笔记38(字符流)
字符输出流:Writer类:使用时候需要它的子类 局限性:只能写文本文件,无法写其他文件 方法: package demo; import java.io.FileWriter; import jav ...
- JAVA学习笔记16——线程的创建和启动
Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例.每个线程的作用是完成一定的任务,实际上就是执行一段程序流(一段顺序执行的代码).Java使用线程执行体来代表这段 ...
- Java学习笔记(7)---流(Stream),文件(File)
1.Stream流 a.定义: Java.io 包几乎包含了所有操作输入.输出需要的类.所有这些流类代表了输入源和输出目标. Java.io 包中的流支持很多种格式,比如:基本类型.对象.本地化字符集 ...
- Java 学习笔记(16)——Java数据库操作
数据库操作是程序设计中十分重要的一个部分,Java内置JDBC来操作数据库 JDBC使用 JDBC--Java Database connecting Java数据库连接:本质上JDBC定义了操作数据 ...
随机推荐
- vs.net 效率提升-自定义快捷键
工欲善其事必先利其器,记录一下自己开发时常用的几个自定义的快捷键.做了这么多年了用着还是比较顺手的分享下~~~~设置时有时设置不成功,非得一项一项设置才可以~~~ 设置自定义快捷键位置:vs.net- ...
- RxSwift 系列(八)
前言 本篇文章我们将学习RxSwift中的错误处理,包括: catchErrorJustReturn catchError retry retry(_:) catchErrorJustReturn 遇 ...
- Python操作Mongo数据库
连接数据库 import pymongo # 连接到数据库,以下两种方式均可 client = pymongo.MongoClient(host='localhost', port=27017) cl ...
- android fragment activity 区别
韩梦飞沙 韩亚飞 313134555@qq.com yue31313 han_meng_fei_sha fragment 负责一个模块 的展示. 由 活动 管理. 碎片 可以 解决 太多活动 ...
- [BZOJ4338][BJOI2015]糖果(扩展Lucas)
先求出式子$P_{C_{K+m-1}^{m}}^{n}$,然后对于排列直接$O(n)$求解,对于组合用扩展Lucas求解. 但这题数据并没有保证任何一个模数的质因子的$p^k$在可线性处理的范围内,于 ...
- [HEOI2013]SAO
题目大意: 一个有向无环图上有n个结点, 现在告诉你n-1个条件(x,y),表示x和y的先后关系. 问原图共有几种可能的拓扑序? 思路: 树形DP. f[i][j]表示对于第i个结点,有j个点在它前面 ...
- Java基础学习——多线程之创建任务
这次来盘点一下Java中用线程执行任务的写法. 1.扩展Thread 最基本的实现方法是在创建一个继承Thread的新类,在其中覆盖run()方法执行任务. public class MyThread ...
- HBase EndPoint加载失败
概述 参考博客(http://blog.csdn.net/carl810224/article/details/52224441)编写EndPoint协处理器,编写完成后使用Maven打包(使用ass ...
- JDK源码(1.7) -- java.util.Map<K,V>
java.util.Map<K,V> 源码分析 --------------------------------------------------------------------- ...
- [转] Spring MVC 4.1.3 + MyBatis 零基础搭建Web开发框架
首先感谢一下润和软件,指引我走上了Spring MVC Web开发的道路. 下面进入正题 搭建开发环境: Netbeans8.0.2 + MySql5.6 + JDK1.7 + tomcat8.0.1 ...