diff --git a/SequenceAnalysis/src/org/labkey/sequenceanalysis/SequenceAnalysisController.java b/SequenceAnalysis/src/org/labkey/sequenceanalysis/SequenceAnalysisController.java index a84752efd..9e2e7f686 100644 --- a/SequenceAnalysis/src/org/labkey/sequenceanalysis/SequenceAnalysisController.java +++ b/SequenceAnalysis/src/org/labkey/sequenceanalysis/SequenceAnalysisController.java @@ -170,6 +170,7 @@ import org.labkey.sequenceanalysis.util.ChainFileValidator; import org.labkey.sequenceanalysis.util.FastqUtils; import org.labkey.sequenceanalysis.util.SequenceUtil; +import org.labkey.vfs.FileLike; import org.springframework.beans.PropertyValues; import org.springframework.validation.BindException; import org.springframework.validation.Errors; @@ -2016,22 +2017,22 @@ else if (!d.getFile().exists()) } else if (o.has("relPath") || o.has("fileName")) { - File f; + FileLike f; if (o.opt("relPath") == null) { if (path != null) { - f = pr.resolvePath(path); - f = new File(f, o.getString("fileName")); + f = pr.resolvePathToFileLike(path); + f = f.resolveFile(Path.parse(o.getString("fileName"))); } else { - f = pr.resolvePath(o.getString("fileName")); + f = pr.resolvePathToFileLike(o.getString("fileName")); } } else { - f = pr.resolvePath(o.getString("relPath")); + f = pr.resolvePathToFileLike(o.getString("relPath")); } if (f == null || !f.exists()) @@ -2039,7 +2040,7 @@ else if (o.has("relPath") || o.has("fileName")) throw new PipelineValidationException("Unknown file: " + o.getString("relPath") + " / " + o.getString("fileName")); } - ret.add(f); + ret.add(f.toNioPathForRead().toFile()); } else if (o.opt("filePath") != null) { @@ -2555,8 +2556,8 @@ protected File getTargetFile(String filename) throws IOException try { - File targetDirectory = AssayFileWriter.ensureUploadDirectory(getContainer(), "sequenceOutputs"); - return AssayFileWriter.findUniqueFileName(filename, targetDirectory); + FileLike targetDirectory = AssayFileWriter.ensureUploadDirectory(getContainer(), "sequenceOutputs"); + return AssayFileWriter.findUniqueFileName(filename, targetDirectory).toNioPathForWrite().toFile(); } catch (ExperimentException e) { @@ -2688,8 +2689,8 @@ protected File getTargetFile(String filename) throws IOException try { - File targetDirectory = AssayFileWriter.ensureUploadDirectory(getContainer()); - return AssayFileWriter.findUniqueFileName(filename, targetDirectory); + FileLike targetDirectory = AssayFileWriter.ensureUploadDirectory(getContainer()); + return AssayFileWriter.findUniqueFileName(filename, targetDirectory).toNioPathForWrite().toFile(); } catch (ExperimentException e) { @@ -2853,8 +2854,8 @@ protected File getTargetFile(String filename) throws IOException try { - File targetDirectory = AssayFileWriter.ensureUploadDirectory(getContainer()); - return AssayFileWriter.findUniqueFileName(filename, targetDirectory); + FileLike targetDirectory = AssayFileWriter.ensureUploadDirectory(getContainer()); + return AssayFileWriter.findUniqueFileName(filename, targetDirectory).toNioPathForWrite().toFile(); } catch (ExperimentException e) { @@ -3643,7 +3644,7 @@ else if (fastaFileType.isType(data.getFile())) } } - File dict = new File(data.getFile().getParentFile(), FileUtil.getBaseName(data.getFile()) + ".dict"); + File dict = FileUtil.appendName(data.getFile().getParentFile(), FileUtil.getBaseName(data.getFile()) + ".dict"); if (dict.exists()) { files.add(dict); @@ -4142,10 +4143,10 @@ public ApiResponse execute(ImportOutputFilesForm form, BindException errors) thr return null; } - File targetDirectory = AssayFileWriter.ensureUploadDirectory(getContainer(), "sequenceOutputs"); + FileLike targetDirectory = AssayFileWriter.ensureUploadDirectory(getContainer(), "sequenceOutputs"); if (!targetDirectory.exists()) { - targetDirectory.mkdirs(); + targetDirectory.mkdir(); } if (form.getRecords() != null) @@ -4155,7 +4156,7 @@ public ApiResponse execute(ImportOutputFilesForm form, BindException errors) thr Map> toCreate = new HashMap<>(); for (JSONObject o : JsonUtil.toJSONObjectList(arr)) { - File file = new File(dirData, o.getString("fileName")); + File file = FileUtil.appendName(dirData, o.getString("fileName")); if (!file.exists()) { errors.reject(ERROR_MSG, "Unknown file: " + file.getPath()); @@ -4196,8 +4197,8 @@ public ApiResponse execute(ImportOutputFilesForm form, BindException errors) thr for (File file : toCreate.keySet()) { - File target = AssayFileWriter.findUniqueFileName(file.getName(), targetDirectory); - FileUtils.moveFile(file, target); + FileLike target = AssayFileWriter.findUniqueFileName(file.getName(), targetDirectory); + FileUtils.moveFile(file, target.toNioPathForWrite().toFile()); ExpData data = ExperimentService.get().createData(getContainer(), new DataType("Sequence Output")); data.setName(file.getName()); @@ -4236,14 +4237,14 @@ public ApiResponse execute(ImportOutputFilesForm form, BindException errors) thr } _log.info("moving associated file: " + idx.getPath() + ", to: " + idxTargetName); - File idxTarget = new File(targetDirectory, idxTargetName); + FileLike idxTarget = targetDirectory.resolveChild(idxTargetName); if (idxTarget.exists()) { _log.error("target already exists, skipping: " + idxTargetName); } else { - FileUtils.moveFile(idx, idxTarget); + FileUtils.moveFile(idx, idxTarget.toNioPathForWrite().toFile()); ExpData idxData = ExperimentService.get().createData(getContainer(), new DataType("Sequence Output")); idxData.setName(idxTarget.getName()); diff --git a/SequenceAnalysis/src/org/labkey/sequenceanalysis/analysis/PicardAlignmentMetricsHandler.java b/SequenceAnalysis/src/org/labkey/sequenceanalysis/analysis/PicardAlignmentMetricsHandler.java index bb5c61c56..0bed04f5f 100644 --- a/SequenceAnalysis/src/org/labkey/sequenceanalysis/analysis/PicardAlignmentMetricsHandler.java +++ b/SequenceAnalysis/src/org/labkey/sequenceanalysis/analysis/PicardAlignmentMetricsHandler.java @@ -171,7 +171,7 @@ public void complete(JobContext ctx, List inputs, List metricsFiles = new ArrayList<>(); - File mf = new File(outputDir, FileUtil.getBaseName(o.getFile()) + ".summary.metrics"); + File mf = FileUtil.appendName(outputDir, FileUtil.getBaseName(o.getFile()) + ".summary.metrics"); if (mf.exists()) { metricsFiles.add(mf); @@ -181,7 +181,7 @@ else if (collectSummary) throw new PipelineJobException("Missing file: " + mf.getPath()); } - File mf2 = new File(outputDir, FileUtil.getBaseName(o.getFile()) + ".insertsize.metrics"); + File mf2 = FileUtil.appendName(outputDir, FileUtil.getBaseName(o.getFile()) + ".insertsize.metrics"); if (mf2.exists()) { metricsFiles.add(mf2); @@ -199,7 +199,7 @@ else if (collectInsertSize) } } - File mf3 = new File(outputDir, FileUtil.getBaseName(o.getFile()) + ".wgs.metrics"); + File mf3 = FileUtil.appendName(outputDir, FileUtil.getBaseName(o.getFile()) + ".wgs.metrics"); if (mf3.exists()) { metricsFiles.add(mf3); @@ -209,7 +209,7 @@ else if (collectWgs) throw new PipelineJobException("Missing file: " + mf3.getPath()); } - File mf4 = new File(outputDir, FileUtil.getBaseName(o.getFile()) + ".wgsNonZero.metrics"); + File mf4 = FileUtil.appendName(outputDir, FileUtil.getBaseName(o.getFile()) + ".wgsNonZero.metrics"); if (mf4.exists()) { metricsFiles.add(mf4); @@ -284,7 +284,7 @@ public void processFilesRemote(List inputFiles, JobContext c { job.getLogger().info("calculating summary metrics"); job.setStatus(PipelineJob.TaskStatus.running, "CALCULATING SUMMARY METRICS"); - File metricsFile = new File(ctx.getOutputDir(), FileUtil.getBaseName(o.getFile()) + ".summary.metrics"); + File metricsFile = FileUtil.appendName(ctx.getOutputDir(), FileUtil.getBaseName(o.getFile()) + ".summary.metrics"); AlignmentSummaryMetricsWrapper wrapper = new AlignmentSummaryMetricsWrapper(job.getLogger()); wrapper.executeCommand(o.getFile(), ctx.getSequenceSupport().getCachedGenome(o.getLibrary_id()).getWorkingFastaFile(), metricsFile); } @@ -293,7 +293,7 @@ public void processFilesRemote(List inputFiles, JobContext c { job.getLogger().info("calculating wgs metrics"); job.setStatus(PipelineJob.TaskStatus.running, "CALCULATING WGS METRICS"); - File wgsMetricsFile = new File(ctx.getOutputDir(), FileUtil.getBaseName(o.getFile()) + ".wgs.metrics"); + File wgsMetricsFile = FileUtil.appendName(ctx.getOutputDir(), FileUtil.getBaseName(o.getFile()) + ".wgs.metrics"); CollectWgsMetricsWrapper wgsWrapper = new CollectWgsMetricsWrapper(job.getLogger()); wgsWrapper.executeCommand(o.getFile(), wgsMetricsFile, ctx.getSequenceSupport().getCachedGenome(o.getLibrary_id()).getWorkingFastaFile()); } @@ -302,7 +302,7 @@ public void processFilesRemote(List inputFiles, JobContext c { job.getLogger().info("calculating wgs metrics over non zero positions"); job.setStatus(PipelineJob.TaskStatus.running, "CALCULATING WGS METRICS"); - File wgsMetricsFile = new File(ctx.getOutputDir(), FileUtil.getBaseName(o.getFile()) + ".wgsNonZero.metrics"); + File wgsMetricsFile = FileUtil.appendName(ctx.getOutputDir(), FileUtil.getBaseName(o.getFile()) + ".wgsNonZero.metrics"); CollectWgsMetricsWithNonZeroCoverageWrapper wgsWrapper = new CollectWgsMetricsWithNonZeroCoverageWrapper(job.getLogger()); wgsWrapper.executeCommand(o.getFile(), wgsMetricsFile, ctx.getSequenceSupport().getCachedGenome(o.getLibrary_id()).getWorkingFastaFile()); } @@ -311,8 +311,8 @@ public void processFilesRemote(List inputFiles, JobContext c { job.getLogger().info("calculating insert size metrics"); job.setStatus(PipelineJob.TaskStatus.running, "CALCULATING INSERT SIZE METRICS"); - File metricsFile = new File(ctx.getOutputDir(), FileUtil.getBaseName(o.getFile()) + ".insertsize.metrics"); - File metricsHistogram = new File(ctx.getOutputDir(), FileUtil.getBaseName(o.getFile()) + ".insertsize.metrics.pdf"); + File metricsFile = FileUtil.appendName(ctx.getOutputDir(), FileUtil.getBaseName(o.getFile()) + ".insertsize.metrics"); + File metricsHistogram = FileUtil.appendName(ctx.getOutputDir(), FileUtil.getBaseName(o.getFile()) + ".insertsize.metrics.pdf"); CollectInsertSizeMetricsWrapper wrapper = new CollectInsertSizeMetricsWrapper(job.getLogger()); wrapper.executeCommand(o.getFile(), metricsFile, metricsHistogram, ctx.getSequenceSupport().getCachedGenome(o.getLibrary_id()).getWorkingFastaFile()); } @@ -323,7 +323,7 @@ public void processFilesRemote(List inputFiles, JobContext c job.setStatus(PipelineJob.TaskStatus.running, "RUNNING MARKDUPLICATES"); MarkDuplicatesWrapper wrapper = new MarkDuplicatesWrapper(job.getLogger()); File metricsFile = wrapper.getMetricsFile(o.getFile()); - File tempBam = new File(ctx.getOutputDir(), FileUtil.getBaseName(o.getFile()) + ".markDuplicates.bam"); + File tempBam = FileUtil.appendName(ctx.getOutputDir(), FileUtil.getBaseName(o.getFile()) + ".markDuplicates.bam"); ctx.getFileManager().addIntermediateFile(tempBam); ctx.getFileManager().addIntermediateFile(SequenceUtil.getExpectedIndex(tempBam)); diff --git a/SequenceAnalysis/src/org/labkey/sequenceanalysis/pipeline/ReferenceLibraryPipelineJob.java b/SequenceAnalysis/src/org/labkey/sequenceanalysis/pipeline/ReferenceLibraryPipelineJob.java index f44a37a66..37f9421dc 100644 --- a/SequenceAnalysis/src/org/labkey/sequenceanalysis/pipeline/ReferenceLibraryPipelineJob.java +++ b/SequenceAnalysis/src/org/labkey/sequenceanalysis/pipeline/ReferenceLibraryPipelineJob.java @@ -22,6 +22,8 @@ import org.labkey.sequenceanalysis.SequenceAnalysisManager; import org.labkey.sequenceanalysis.SequenceAnalysisSchema; import org.labkey.sequenceanalysis.model.ReferenceLibraryMember; +import org.labkey.vfs.FileLike; +import org.labkey.vfs.FileSystemLike; import java.io.File; import java.io.IOException; @@ -107,7 +109,7 @@ protected void writeParameters(JSONObject params) throws IOException public File getSerializedLibraryMembersFile() { - return new File(getDataDirectory(), FileUtil.getBaseName(getLogFile()) + ".json"); + return FileUtil.appendName(getDataDirectory(), FileUtil.getBaseName(getLogFile()) + ".json"); } //for recreating an existing library @@ -193,7 +195,7 @@ public boolean isCreateNew() } @Override - protected File createLocalDirectory(PipeRoot pipeRoot) + protected FileLike createLocalDirectory(PipeRoot pipeRoot) { if (PipelineJobService.get().getLocationType() != PipelineJobService.LocationType.WebServer) { @@ -211,7 +213,7 @@ protected File createLocalDirectory(PipeRoot pipeRoot) outputDir.mkdirs(); } - return outputDir; + return new FileSystemLike.Builder(outputDir).tempDir().root(); } @Override diff --git a/SequenceAnalysis/src/org/labkey/sequenceanalysis/pipeline/SequenceJob.java b/SequenceAnalysis/src/org/labkey/sequenceanalysis/pipeline/SequenceJob.java index f4c1c4826..0ef25c152 100644 --- a/SequenceAnalysis/src/org/labkey/sequenceanalysis/pipeline/SequenceJob.java +++ b/SequenceAnalysis/src/org/labkey/sequenceanalysis/pipeline/SequenceJob.java @@ -44,6 +44,7 @@ import org.labkey.api.view.ViewBackgroundInfo; import org.labkey.api.writer.PrintWriters; import org.labkey.sequenceanalysis.util.SequenceUtil; +import org.labkey.vfs.FileLike; import java.io.BufferedReader; import java.io.File; @@ -67,8 +68,8 @@ public class SequenceJob extends PipelineJob implements FileAnalysisJobSupport, private Integer _experimentRunRowId; private String _jobName; private String _description; - private File _webserverJobDir; - private File _parentWebserverJobDir; + private FileLike _webserverJobDir; + private FileLike _parentWebserverJobDir; private String _folderPrefix; private List _inputFiles; private List _outputsToCreate = new ArrayList<>(); @@ -95,10 +96,10 @@ protected SequenceJob(SequenceJob parentJob, String jobName, String subdirectory _description = parentJob._description; _support = parentJob.getSequenceSupport(); _parentWebserverJobDir = parentJob._webserverJobDir; - _webserverJobDir = new File(parentJob._webserverJobDir, subdirectory); + _webserverJobDir = parentJob._webserverJobDir.resolveChild(subdirectory); if (!_webserverJobDir.exists()) { - _webserverJobDir.mkdirs(); + _webserverJobDir.mkdir(); } _folderPrefix = parentJob._folderPrefix; @@ -157,7 +158,8 @@ protected void addCustomParams(JSONObject params) private Path _getLogFile() { - return AssayFileWriter.findUniqueFileName((FileUtil.makeLegalName(_jobName) + ".log"), getDataDirectory().toPath()); + var file = AssayFileWriter.findUniqueFileName((FileUtil.makeLegalName(_jobName) + ".log"), getDataDirectoryFileObject()); + return file.toNioPathForWrite(); } @Override @@ -187,9 +189,9 @@ public void setDescription(String description) _description = description; } - protected File createLocalDirectory(PipeRoot pipeRoot) throws IOException + protected FileLike createLocalDirectory(PipeRoot pipeRoot) throws IOException { - File webserverOutDir = new File(pipeRoot.getRootPath(), _folderPrefix + "Pipeline"); + FileLike webserverOutDir = pipeRoot.getRootFileLike().resolveChild(_folderPrefix + "Pipeline"); if (!webserverOutDir.exists()) { webserverOutDir.mkdir(); @@ -199,7 +201,7 @@ protected File createLocalDirectory(PipeRoot pipeRoot) throws IOException webserverOutDir = AssayFileWriter.findUniqueFileName(folderName, webserverOutDir); if (!webserverOutDir.exists()) { - webserverOutDir.mkdirs(); + webserverOutDir.mkdir(); } return webserverOutDir; @@ -312,19 +314,26 @@ public String getBaseNameForFileType(FileType fileType) @Override public File getDataDirectory() + { + return _webserverJobDir.toNioPathForWrite().toFile(); + } + + public FileLike getDataDirectoryFileObject() { return _webserverJobDir; } public File getWebserverDir(boolean forceParent) { - return forceParent && isSplitJob() ? _parentWebserverJobDir : _webserverJobDir; + return forceParent && isSplitJob() ? + _parentWebserverJobDir.toNioPathForWrite().toFile() : + _webserverJobDir.toNioPathForWrite().toFile(); } @Override public File getAnalysisDirectory() { - return _webserverJobDir; + return _webserverJobDir.toNioPathForWrite().toFile(); } @Override @@ -355,14 +364,15 @@ public ParamParser createParamParser() @Override public File getParametersFile() { - return new File(_parentWebserverJobDir == null ? _webserverJobDir : _parentWebserverJobDir, _folderPrefix + ".json"); + var dir = _parentWebserverJobDir == null ? _webserverJobDir : _parentWebserverJobDir; + return FileUtil.appendName(dir.toNioPathForWrite().toFile(),_folderPrefix + ".json"); } @Nullable @Override public File getJobInfoFile() { - return new File(_webserverJobDir, FileUtil.makeLegalName(_jobName) + ".job.json"); + return FileUtil.appendName(_webserverJobDir.toNioPathForWrite().toFile(), FileUtil.makeLegalName(_jobName) + ".job.json"); } @Override @@ -390,7 +400,7 @@ public SequenceJobSupportImpl getSequenceSupport() protected File getCachedSupportFile() { - return new File(getLogFile().getParentFile(), "sequenceSupport.json.gz"); + return FileUtil.appendName(getLogFile().getParentFile(), "sequenceSupport.json.gz"); } private SequenceJobSupportImpl readSupportFromDisk() throws IOException @@ -530,7 +540,7 @@ public void setExperimentRunRowId(Integer experimentRunRowId) public File findFile(String name) { - return new File(getAnalysisDirectory(), name); + return FileUtil.appendName(getAnalysisDirectory(), name); } protected static XarGeneratorFactorySettings getXarGenerator() throws CloneNotSupportedException @@ -577,14 +587,14 @@ public static class TestCase extends Assert public void testSerializeSupport() throws Exception { ExpData d1 = ExperimentService.get().createData(ContainerManager.getHomeContainer(), new DataType("testCase")); - d1.setDataFileURI(new File(FileUtil.getTempDirectory(), "foo.txt").toURI()); + d1.setDataFileURI(FileUtil.appendName(FileUtil.getTempDirectory(), "foo.txt").toURI()); SequenceJob job = new SequenceJob(); job._support = new SequenceJobSupportImpl(); job._support.cacheExpData(d1); - job.setLogFile(new File(FileUtil.getTempDirectory(), "testJob.log").toPath()); + job.setLogFile(FileUtil.appendName(FileUtil.getTempDirectory(), "testJob.log").toPath()); - File testFile = new File(FileUtil.getTempDirectory(), "testJob.json.txt"); + File testFile = FileUtil.appendName(FileUtil.getTempDirectory(), "testJob.json.txt"); File support = job.getCachedSupportFile(); if (support.exists()) { @@ -624,7 +634,7 @@ public File getLocationForCachedInputs(WorkDirectory wd, boolean createIfDoesntE if (localDir == null) { - ret = new File(wd.getDir(), "cachedData"); + ret = FileUtil.appendName(wd.getDir(), "cachedData"); } else { diff --git a/blast/src/org/labkey/blast/BLASTController.java b/blast/src/org/labkey/blast/BLASTController.java index 82a453097..d511beae8 100644 --- a/blast/src/org/labkey/blast/BLASTController.java +++ b/blast/src/org/labkey/blast/BLASTController.java @@ -58,6 +58,7 @@ import org.labkey.api.writer.PrintWriters; import org.labkey.blast.model.BlastJob; import org.labkey.blast.pipeline.BlastDatabasePipelineJob; +import org.labkey.vfs.FileLike; import org.springframework.validation.BindException; import org.springframework.validation.Errors; import org.springframework.web.multipart.MultipartHttpServletRequest; @@ -215,8 +216,8 @@ protected File getTargetFile(String filename) throws IOException AssayFileWriter writer = new AssayFileWriter(); try { - File targetDirectory = AssayFileWriter.ensureUploadDirectory(getContainer()); - return AssayFileWriter.findUniqueFileName(filename, targetDirectory); + FileLike targetDirectory = AssayFileWriter.ensureUploadDirectory(getContainer()); + return AssayFileWriter.findUniqueFileName(filename, targetDirectory).toNioPathForWrite().toFile(); } catch (ExperimentException e) { @@ -263,14 +264,14 @@ public String getResponse(RunBlastForm form, Map> fil AssayFileWriter writer = new AssayFileWriter(); try { - File targetDirectory = AssayFileWriter.ensureUploadDirectory(getContainer()); - File input = AssayFileWriter.findUniqueFileName("blast", targetDirectory); - input.createNewFile(); - try (PrintWriter fw = PrintWriters.getPrintWriter(input)) + FileLike targetDirectory = AssayFileWriter.ensureUploadDirectory(getContainer()); + FileLike input = AssayFileWriter.findUniqueFileName("blast", targetDirectory); + input.createFile(); + try (PrintWriter fw = PrintWriters.getPrintWriter(input.openOutputStream())) { fw.write(form.getQuery()); } - inputFiles.add(input); + inputFiles.add(input.toNioPathForRead().toFile()); } catch (ExperimentException e) { diff --git a/jbrowse/src/org/labkey/jbrowse/pipeline/JBrowseLucenePipelineJob.java b/jbrowse/src/org/labkey/jbrowse/pipeline/JBrowseLucenePipelineJob.java index 4c4f6ad92..4ae81ac0f 100644 --- a/jbrowse/src/org/labkey/jbrowse/pipeline/JBrowseLucenePipelineJob.java +++ b/jbrowse/src/org/labkey/jbrowse/pipeline/JBrowseLucenePipelineJob.java @@ -18,6 +18,7 @@ import org.labkey.api.security.User; import org.labkey.api.sequenceanalysis.pipeline.SequencePipelineService; import org.labkey.api.sequenceanalysis.run.DISCVRSeqRunner; +import org.labkey.api.util.FileUtil; import org.labkey.api.util.GUID; import org.labkey.api.util.PageFlowUtil; import org.labkey.api.view.ActionURL; @@ -58,7 +59,7 @@ public JBrowseLucenePipelineJob(Container c, User user, PipeRoot pipeRoot, Strin _infoFields = infoFields; _allowLenientLuceneProcessing = allowLenientLuceneProcessing; - setLogFile(AssayFileWriter.findUniqueFileName("jbrowse-lucene" + new GUID() + ".log", JBrowseManager.get().getBaseDir(c, true).toPath())); + setLogFile(AssayFileWriter.findUniqueFileName("jbrowse-lucene" + new GUID() + ".log", JBrowseManager.get().getBaseDir(c, true))); } public static class JBrowseLucenePipelineProvider extends PipelineProvider @@ -262,6 +263,6 @@ private static void recursivelyChangeDirectoryPermissions(File f) throws IOExcep public static File getFieldListFile(File indexDir) { - return new File(indexDir, "fieldList.txt"); + return FileUtil.appendName(indexDir, "fieldList.txt"); } }