HDFS分布式文件系统:
优点:支持超大文件存储、流式访问、一次写入多次读取。
缺点:不适应大量小文件、不适应低时延的数据访问、不适应多用户访问任意修改文件。
1.hadoop用于大数据处理,在数据量较小时,并不适用于实时性强的任务,并不是所有的job放到hadoop上,性能都会提升。
2.大量小文件的情况下会极大的降低系统的性能,所以处理前需要先将少文件聚合成大文件,map的输出也应该首先combine在传输给reduce。
3.数据传输时的IO开销,存储在内存中还是硬盘中,节点之间共享数据的分发,都是实践中需要考虑的问题。
涉及的节点:Namenode、 secondaryNameNode、 DataNode
HDFS将大文件切分成小文件块(64M)分布式存储在DataNode节点上,Namenode上仅仅记录元数据的信息。
文件的常用操作:
创建、删除、读、写、追加、重命名、查看属性、更改属性、创建文件夹、移动文件、遍历所有文件、删除文件夹、重命名、判断是否是目录、判断是否存在。
1.shell下提供的文件操作:
./hadoop fs -help
1.1 列出文件
./hadoop fs -list 文件路径
1.2 上传文件
./hadoop fs -put <srcpath> <destpath>
1.3 下载文件
./hadoo fs -get <srcpath> <destpath>
1.4 删除文件或文件夹
./hadoop fs -rmr 文件路径
1.5 查看文本文件
./hadoop fs -cat 文件路径
1.6 文件存储负载均衡
./start-balanser.sh
1.7 查看文件系统的统计信息
./hadoop dfsadmin -report
2.代码中的文件操作(API):
一般是使用java创建本地的文件流, 使用fs创建hdfs上的文件流, 然后使用相关的Utils在两者之间进行传递。与外界有交互的时候一定要首先创建流。
hdfs 文件相关的操作都是通过FileSystem进行的, 如文件的(create、open、delete、copyFromLocalFile、exists、listStatus、rename、getFileBlockLocations、
getDatanodeStatus
fs是HDFS文件系统对外的接口,同样的还有LocalFileSystem、DistributedFileSystem
创建fs的时候URI.create()这句话要加上,不然会说Wrong FS: expected file:\\\
2.1 创建(写):
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
public class FileCopy {
public static void main(String[] args)throws Exception{
if (args.length != 2){
System.err.println("Usage : filecopy <source> <dest>");
System.exit(2);
}
Configuration conf = new Configuration();
InputStream in = new BufferedInputStream(new FileInputStream(args[0]));
FileSystem fs = FileSystem.get(URI.create(args[1]), conf);
OutputStream out = fs.create(new Path(args[1]));
IOUtils.copyBytes(in, out, 512,true);
}
}
2.2 打开(读):
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(URI.create(args[0]), conf);
InputStream in = null; try{ in = fs.open(new Path(args[0])); IOUtils.copyBytes(in, System.out, 4096,false); }finally{ IOUtils.closeStream(in); }
2.3 将数组里的内容写入文件
Configruation conf = new Configuration();
FileSystem fs = FileSystem.get(URI.create(args[0]),conf);
Path path = new Path("文件路径");
byte[] buf = "hello world!".getBytes();
FSDataOutputStream out = fs.create(path);
out.write(buf, 0, buf,length);
2.4 直接将本地文件上传
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(URI.create("hdfs文件路径"),conf);
Path src = new Path("本地文件路径");
Path dest = new Path("hdfs文件路径");
fs.copyFromLocalFiles(src, dest);
2.5 删除:
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(URI.create(args[0]),conf);
fs.delete(new Path(args[0]), false);
2.6 判断文件是否存在
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
Path path = new Path("你的文件路径");
boolean isExists = fs.exists(path);
2.7 重命名
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
Path src = new Path("路径/源文件名");
Path dst = new Path("路径/目的文件名");
boolean isRename = fs.rename(src, dst);
2.8 显示属性:
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(URI.create(args[0]), conf);
FileStatus stat = fs.getFileStatus(new Path(args[0]));
System.out.println("路径:\t"+stat.getPath());
System.out.println("长度:\t"+stat.getLen());
System.out.println("用户:\t"+stat.getOwner());
System.out.println("组:\t"+stat.getGroup());
System.out.println("块大小:\t"+stat.getBlockSize());
System.out.println("修改时间:\t"+stat.getModificationTime());
System.out.println("权限:\t"+stat.getPermission().toString());
System.out.println("备份:\t"+stat.getReplication());
System.out.println("文件夹?:\t"+stat.isDir());
2.9 遍历文件:
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(URI.create(args[0]), conf);
FileStatus[] status = fs.listStatus(new Path(args[0]));
Path[] listedPaths = FileUtil.stat2Paths(status);
for (Path p : listedPaths){
System.out.println(p);
}
2.10查找文件在hdfs集群中的位置
package cc.test.fileLocation;
import java.net.URI;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.BlockLocation;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
public class FileLocation {
public static void main(String[] args)throws Exception{
Configuration conf = new Configuration();
String s = "hdfs://MASTERPC:9000/home/Fea.txt";
FileSystem fs = FileSystem.get(URI.create(s),conf);
FileStatus stat = fs.getFileStatus(new Path(s));
BlockLocation[] blkLocations = fs.getFileBlockLocations(stat, 0, stat.getLen());
for (int i=0; i<blkLocations.length; i++){
System.out.println("block:"+String.valueOf(i)+blkLocations[i].getHosts();
}
}
}
2.11 查找所有的datanode节点:
package cc.test.datenodeName;
import java.net.URI;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.hdfs.DistributedFileSystem;
import org.apache.hadoop.hdfs.protocol.DatanodeInfo;
public class DatanodeName {
public static void main(String[] args)throws Exception{
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(/*URI.create("hdfs://MASTERPC:9000/"),*/conf);
DistributedFileSystem dfs = (DistributedFileSystem)fs;
DatanodeInfo[] dnstats = dfs.getDataNodeStats();
for (int i=0; i<dnstats.length; i++){
System.out.println(dnstats[i].getHostName());
}
}
}
如果在建立fs的时候没有加URI.create(), 会报一下错误:
Exception in thread "main" java.lang.ClassCastException: org.apache.hadoop.fs.LocalFileSystem cannot be cast to org.apache.hadoop.hdfs.DistributedFileSystem
这时由于在eclipse中运行的hadoop程序,默认并不是放到云端执行的,而是eclipse的虚拟云中运行,没有job的调度,也没还有配置文件的读取
路径中如果不加前缀hdfs://MASTERPC:9000则默认是PC的本地文件。(我的猜测)
采用writer将小文件数据聚合成sequence 字节流从而在hdfs中形成大文件。
package cc.test.filesequence;
import java.net.URI;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.io.SequenceFile;
import org.apache.hadoop.io.SequenceFile.CompressionType;
import org.apache.hadoop.io.Text;
public class FileSequence {
private static String[] temValue = {
"hello world",
"hello china",
"hello home",
"hello hadoop"
};
public static void main(String[] args)throws Exception{
if (args.length != 2){
System.err.println("Usage: fileSeq: <src> <dest>");
System.exit(2);
}
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(URI.create(args[1]), conf);
Path path = new Path(args[1]);
Text key = new Text();
BytesWritable value = new BytesWritable();
SequenceFile.Writer writer = null;
try{
writer = SequenceFile.createWriter(fs, conf, path, key.getClass(), value.getClass(), CompressionType.BLOCK);
for (int i = 0; i< 5000; i++){
key.set(String.valueOf(i));
value.set(new BytesWritable(temValue[i%(temValue.length)].getBytes()));
writer.append(key, value);
}
}finally{
IOUtils.closeStream(writer);
}
System.out.println("done");
}
}
package cc.test.serializeTest;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Writable;
import org.apache.hadoop.util.StringUtils;
public class SerializeTest {
public static byte[] serialize(Writable w)throws IOException{
ByteArrayOutputStream out = new ByteArrayOutputStream();
DataOutputStream dataout = new DataOutputStream(out);
w.write(dataout);
dataout.close();
return out.toByteArray();
}
public static byte[] deserialize(Writable w, byte[] bytes)throws IOException{
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
DataInputStream datain = new DataInputStream(in);
w.readFields(datain);
datain.close();
return bytes;
}
public static void main(String[] args)throws Exception{
IntWritable intw = new IntWritable(9);
byte[] bytes = serialize(intw);
String bytes_str = StringUtils.byteToHexString(bytes);
System.out.println(bytes_str);
IntWritable intw2 = new IntWritable();
deserialize(intw2, bytes);
System.out.println(intw2);
}
}
00000009
9