【问题标题】:Converting from FSDataInputStream to FileInputStream从 FSDataInputStream 转换为 FileInputStream
【发布时间】:2013-09-30 16:50:51
【问题描述】:

我是 Hadoop HDFS 的新手,对 Java 很生疏,我需要一些帮助。我正在尝试从 HDFS 读取文件并计算该文件的 MD5 哈希值。一般 Hadoop 配置如下。

private FSDataInputStream hdfsDIS;
private FileInputStream FinputStream;
private FileSystem hdfs;
private Configuration myConfig;

myConfig.addResource("/HADOOP_HOME/conf/core-site.xml");
myConfig.addResource("/HADOOP_HOME/conf/hdfs-site.xml");

hdfs = FileSystem.get(new URI("hdfs://NodeName:54310"), myConfig);

hdfsDIS = hdfs.open(hdfsFilePath);

函数hdfs.open(hdfsFilePath)返回一个FSDataInputStream

问题是我只能从 HDFS 中获取 FSDataInputStream,但我想从中获取 FileInputStream

下面的代码执行散列部分,并改编自我在 StackOverflow 某处找到的内容(现在似乎找不到指向它的链接)。

FileInputStream FinputStream = hdfsDIS;   // <---This is where the problem is
MessageDigest md;
    try {
        md = MessageDigest.getInstance("MD5");  
        FileChannel channel = FinputStream.getChannel();
        ByteBuffer buff = ByteBuffer.allocate(2048);

        while(channel.read(buff) != -1){
            buff.flip();
            md.update(buff);
            buff.clear();
        }
        byte[] hashValue = md.digest();

        return toHex(hashValue);
    }
    catch (NoSuchAlgorithmException e){
        return null;
    } 
    catch (IOException e){
        return null;
    }

我需要FileInputStream 的原因是因为执行散列的代码使用了FileChannel,这可能会提高从文件中读取数据的效率。

有人可以告诉我如何将FSDataInputStream 转换为FileInputStream

【问题讨论】:

  • 您是否至少尝试过只是使用现有流进行散列?您说使用FileChannel“据说”会提高效率——您是否对此进行了测试并发现您实际上需要任何可能获得的性能改进?
  • 实际上,我没有尝试使用“现有流”,但我想我不妨试试看它是否有效。顺便说一句,我找到了我从 (stackoverflow.com/a/9322214/2105711) 获取代码的链接
  • 好的,所以我已经使用了现有的流,从中读取,计算了哈希并且它可以工作。也许我现在可以忘记所谓的“性能改进”。虽然希望有一天有人会想出我正在寻找的使用 NIO FileChannels 的解决方案。 (如果它被认为对大文件有用,那就是)

标签: java hadoop hash


【解决方案1】:

将其用作InputStream:

MessageDigest md;
try {
    md = MessageDigest.getInstance("MD5");  
    byte[] buff = new byte[2048];
    int count;

    while((count = hdfsDIS.read(buff)) != -1){
        md.update(buff, 0, count);
    }
    byte[] hashValue = md.digest();

    return toHex(hashValue);
}
catch (NoSuchAlgorithmException e){
    return null;
} 
catch (IOException e){
    return null;
}

执行散列的代码使用 FileChannel,据说可以提高从文件中读取数据的效率

在这种情况下不是。如果您只是将数据复制到另一个通道,它只会提高效率,如果您使用 DirectByteBuffer. 如果您正在处理数据,就像这里一样,它没有任何区别。读还是读。

【讨论】:

  • 是的,这或多或少是我之前建议的避免FileChannel 所做的。也感谢您的进一步解释。
【解决方案2】:

您可以将FSDataInputStream 用作普通的InputStream,并将其传递给Channels.newChannel 以获取ReadableByteChannel 而不是FileChannel。这是一个更新的版本:

InputStream inputStream = hdfsDIS;
MessageDigest md;
try {
    md = MessageDigest.getInstance("MD5");  
    ReadableByteChannel channel = Channels.newChannel(inputStream);
    ByteBuffer buff = ByteBuffer.allocate(2048);

    while(channel.read(buff) != -1){
        buff.flip();
        md.update(buff);
        buff.clear();
    }
    byte[] hashValue = md.digest();

    return toHex(hashValue);
}
catch (NoSuchAlgorithmException e){
    return null;
} 
catch (IOException e){
    return null;
}

【讨论】:

  • 明天可能会检查一下,让您知道它是否真的可以作为更好的解决方案。
【解决方案3】:

你不能做那个作业,因为:

java.lang.Object
由 java.io.InputStream 扩展
由 java.io.FilterInputStream
扩展 由 java.io.DataInputStream 扩展
由 org.apache.hadoop.fs.FSDataInputStream 扩展

FSDataInputStream 不是 FileInputStream。

也就是说从FSDataInputStream转换为FileInputStream,

您可以使用 FSDataInputStream FileDescriptors 根据 Api 创建一个 FileInputStream

new FileInputStream(hdfsDIS.getFileDescriptor());

不确定它会起作用。

【讨论】:

  • 刚刚测试了这个,它似乎不起作用。它实际上只是默默地失败了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-17
  • 2013-07-09
  • 2015-02-11
相关资源
最近更新 更多