Java 如果我有一个需要文件路径的构造函数,我怎么能;假;如果它被包装在一个罐子里?

Java 如果我有一个需要文件路径的构造函数,我怎么能;假;如果它被包装在一个罐子里?,java,jar,hadoop,apache-pig,Java,Jar,Hadoop,Apache Pig,这个问题的背景是,我试图在我编写的pig脚本中使用maxmind java api。。。然而,我不认为有必要了解这两种情况来回答这个问题 maxmind API有一个构造函数,它需要一个名为GeoIP.dat的文件的路径,该文件是一个逗号分隔的文件,其中包含所需的信息 我有一个包含API的jar文件,还有一个包装类,它实例化并使用该类。我的想法是将GeoIP.dat文件打包到jar中,然后作为jar文件中的资源访问它。问题是我不知道如何构造构造函数可以使用的路径 查看API,以下是加载文件的方式

这个问题的背景是,我试图在我编写的pig脚本中使用maxmind java api。。。然而,我不认为有必要了解这两种情况来回答这个问题

maxmind API有一个构造函数,它需要一个名为GeoIP.dat的文件的路径,该文件是一个逗号分隔的文件,其中包含所需的信息

我有一个包含API的jar文件,还有一个包装类,它实例化并使用该类。我的想法是将GeoIP.dat文件打包到jar中,然后作为jar文件中的资源访问它。问题是我不知道如何构造构造函数可以使用的路径

查看API,以下是加载文件的方式:

public LookupService(String databaseFile) throws IOException {
    this(new File(databaseFile));
}


public LookupService(File databaseFile) throws IOException {
    this.databaseFile = databaseFile;
    this.file = new RandomAccessFile(databaseFile, "r");
    init();
}
我之所以粘贴它,是因为我并不反对编辑API本身来实现这一点(如果必要的话),但我不知道如何复制我自己的功能。理想情况下,我希望将其放入文件格式,否则编辑API将是一件非常繁琐的事情


这可能吗?

使用
classloader.getResource(…)
方法在类路径中查找文件,这将从JAR文件中提取它

这意味着您必须更改现有代码以覆盖加载。如何做到这一点的细节在很大程度上取决于您现有的代码和环境。在某些情况下,子类化和向框架注册子类可能会起作用。在其他情况下,您可能必须确定类沿类路径加载的顺序,并在类路径中“更早”放置一个具有相同符号的类。

尝试:

new File(MyWrappingClass.class.getResource(<resource>).toURI())
新文件(MyWrappingClass.class.getResource().toURI())

将数据转储到临时文件,并将临时文件馈送到该文件

File tmpFile = File.createTempFile("XX", "dat");
tmpFile.deleteOnExit();

InputStream is = MyClass.class.getResourceAsStream("/path/in/jar/XX.dat");
OutputStream os = new FileOutputStream(tmpFile)

read from is, write to os, close

下面是我们如何使用maxmind geoIP

我们将
geoicity.dat
文件放入云中,并在启动流程时使用云位置作为参数。 获取
geoicity.data
文件并创建新的
LookupService
的代码是:

if (DistributedCache.getLocalCacheFiles(context.getConfiguration()) != null) {
    List<Path> localFiles = Utility.arrayToList(DistributedCache.getLocalCacheFiles(context.getConfiguration()));
    for (Path localFile : localFiles) {
        if ((localFile.getName() != null) && (localFile.getName().equalsIgnoreCase("GeoIPCity.dat"))) {
            m_geoipLookupService = new LookupService(new File(localFile.toUri().getPath()));
        }
    }
}
if(DistributedCache.getLocalCacheFiles(context.getConfiguration())!=null){
List localFiles=Utility.arrayToList(DistributedCache.getLocalCacheFiles(context.getConfiguration());
用于(路径localFile:localFiles){
如果((localFile.getName()!=null)&&(localFile.getName().equalsIgnoreCase(“geoicity.dat”)){
m_geoipLookupService=newlookupservice(新文件(localFile.toUri().getPath());
}
}
}
下面是用于运行流程的命令的缩写版本

$HADOOP\u HOME/bin/HADOOP jar/usr/lib/COMPANY/analytics/libjars/MyJar.jar-文件hdfs://PDHadoop1.corp.COMPANY.com:54310/data/geoip/GeoIPCity.dat -libjars/usr/lib/COMPANY/analytics/libjars/geoiplookup.jar

运行MindMax组件的关键组件是
-files
-libjars
。这些是中的通用选项

-文件指定要复制到map reduce群集的逗号分隔文件

-libjars指定要包含在类路径中的逗号分隔的jar文件。

我假设Hadoop使用了
GenericOptionsParser
,因为我在项目中的任何地方都找不到对它的引用

如果将
geoicity.dat
放在can上,并使用
-files
参数指定它,它将被放入本地缓存中,然后映射程序可以在
设置
函数中获取该缓存。它不必在
设置中,但每个映射器只需执行一次,因此是放置它的最佳位置。
然后使用
-libjars
参数指定geoiplookup.jar(或您所称的任何内容),它将能够使用它。我们不会将geoiplookup.jar放在云上。我相信hadoop会根据需要分发jar

我希望这一切都有意义。我对hadoop/mapreduce已经相当熟悉了,但是我没有在项目中编写使用maxmind geoip组件的文章,所以我不得不做一些挖掘工作来充分理解它,以便完成这里的解释

编辑:对
-files
-libjars
-files参数用于通过Hadoop分布式缓存分发文件。在上面的示例中,我们通过Hadoop分布式缓存分发Max Mind geo ip数据文件。我们需要访问Max Mind geo ip数据文件,以将用户的ip地址映射到适当的国家、地区、城市、时区。API要求数据文件在本地显示,这在分布式处理环境中是不可行的(我们无法保证集群中的哪些节点将处理数据)。为了将适当的数据分发到处理节点,我们使用Hadoop分布式缓存基础设施。GenericOptionsParser和ToolRunner使用–file参数自动实现这一点。请注意,我们分发的文件应该在云中可用(HDFS)。
-libjars–libjars用于分发map reduce作业所需的任何其他依赖项。与数据文件一样,我们还需要将依赖库复制到集群中运行作业的节点。GenericOptionsParser和ToolRunner使用–libjars参数自动实现这一点。

推荐的方法之一是使用,而不是尝试将其捆绑到jar中

如果您压缩GeoIP.dat并将其复制到hdfs://host:port/path/GeoIP.dat.zip. 然后将以下选项添加到Pig命令:

pig ...
  -Dmapred.cache.archives=hdfs://host:port/path/GeoIP.dat.zip#GeoIP.dat 
  -Dmapred.create.symlink=yes
...
LookupService LookupService=newlookupservice(“./GeoIP.dat”)
应该在您的UDF中工作,因为文件将在每个节点上的任务本地显示。

这对我很有用

假设您有一个包含GeoLiteCity的包org.foo.bar.util。
URL fileURL = this.getClass().getResource("org/foo/bar/util/GeoLiteCity.dat");
File geoIPData = new File(fileURL.toURI());
LookupService cl = new LookupService(geoIPData, LookupService.GEOIP_MEMORY_CACHE );