【问题标题】:org.springframework.batch.item.ItemStreamException: File is not writable: Spring Batchorg.springframework.batch.item.ItemStreamException:文件不可写:Spring Batch
【发布时间】:2018-07-11 08:04:09
【问题描述】:

在 Spring Boot Batch 项目中,我收到以下错误,不知道这里出了什么问题?

我只是从 mysql DB 中读取表并使用 FlatFileItemWriter 将其写入文件。还使用 Partiontioner 读取代码并将其写入平面文件。 Spring Boot Parent版本2.0.2.RELEASE。

org.springframework.batch.item.ItemStreamException: File is not writable: [C:\Spring_Learning\spring-batch\spring-batch-classic-db\csv\outputs\users.processed201-250.csv]
    at org.springframework.batch.item.util.FileUtils.setUpOutputFile(FileUtils.java:88) ~[spring-batch-infrastructure-4.0.1.RELEASE.jar:4.0.1.RELEASE]
    at org.springframework.batch.item.file.FlatFileItemWriter$OutputState.initializeBufferedWriter(FlatFileItemWriter.java:572) ~[spring-batch-infrastructure-4.0.1.RELEASE.jar:4.0.1.RELEASE]
    at org.springframework.batch.item.file.FlatFileItemWriter$OutputState.access$000(FlatFileItemWriter.java:414) ~[spring-batch-infrastructure-4.0.1.RELEASE.jar:4.0.1.RELEASE]
    at org.springframework.batch.item.file.FlatFileItemWriter.doOpen(FlatFileItemWriter.java:348) ~[spring-batch-infrastructure-4.0.1.RELEASE.jar:4.0.1.RELEASE]
    at org.springframework.batch.item.file.FlatFileItemWriter.open(FlatFileItemWriter.java:338) ~[spring-batch-infrastructure-4.0.1.RELEASE.jar:4.0.1.RELEASE]
    at org.springframework.batch.item.file.FlatFileItemWriter$$FastClassBySpringCGLIB$$bd919dcd.invoke(<generated>) ~[spring-batch-infrastructure-4.0.1.RELEASE.jar:4.0.1.RELEASE]
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-5.0.6.RELEASE.jar:5.0.6.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:746) ~[spring-aop-5.0.6.RELEASE.jar:5.0.6.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.0.6.RELEASE.jar:5.0.6.RELEASE]
    at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:136) ~[spring-aop-5.0.6.RELEASE.jar:5.0.6.RELEASE]
    at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124) ~[spring-aop-5.0.6.RELEASE.jar:5.0.6.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.6.RELEASE.jar:5.0.6.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) ~[spring-aop-5.0.6.RELEASE.jar:5.0.6.RELEASE]
    at org.springframework.batch.item.file.FlatFileItemWriter$$EnhancerBySpringCGLIB$$d3ba3d4f.open(<generated>) ~[spring-batch-infrastructure-4.0.1.RELEASE.jar:4.0.1.RELEASE]
    at org.springframework.batch.item.support.CompositeItemStream.open(CompositeItemStream.java:103) ~[spring-batch-infrastructure-4.0.1.RELEASE.jar:4.0.1.RELEASE]
    at org.springframework.batch.core.step.tasklet.TaskletStep.open(TaskletStep.java:310) ~[spring-batch-core-4.0.1.RELEASE.jar:4.0.1.RELEASE]
    at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:197) ~[spring-batch-core-4.0.1.RELEASE.jar:4.0.1.RELEASE]
    at org.springframework.batch.core.partition.support.TaskExecutorPartitionHandler$1.call(TaskExecutorPartitionHandler.java:139) [spring-batch-core-4.0.1.RELEASE.jar:4.0.1.RELEASE]
    at org.springframework.batch.core.partition.support.TaskExecutorPartitionHandler$1.call(TaskExecutorPartitionHandler.java:136) [spring-batch-core-4.0.1.RELEASE.jar:4.0.1.RELEASE]
    at java.util.concurrent.FutureTask.run(Unknown Source) [na:1.8.0_171]
    at java.lang.Thread.run(Unknown Source) [na:1.8.0_171]

代码

@Bean
    @StepScope
    public FlatFileItemWriter<Payments> slaveWriter(@Value("#{stepExecutionContext[fromId]}") final String fromId,
            @Value("#{stepExecutionContext[toId]}") final String toId) {

        FlatFileItemWriter<Payments> reader = new FlatFileItemWriter<>();
        reader.setResource(new FileSystemResource("csv/outputs/users.processed" + fromId + "-" + toId + ".csv"));
        reader.setAppendAllowed(true);

        reader.setLineAggregator(new DelimitedLineAggregator<Payments>() {
            {
                setDelimiter(",");
                setFieldExtractor(new BeanWrapperFieldExtractor<Payments>() {
                    {
                        setNames(new String[] { "customerNumber", "checkNumber", "paymentDate", "amount"});
                    }
                });
            }
        });
        return reader;
    }

【问题讨论】:

  • 你试过改变输出文件的路径吗?
  • 尝试写入另一个位置,看看是否遇到相同的错误。如果没有,那么您必须确保运行您的 spring 批处理作业的 java 进程有权写入该位置。

标签: spring spring-boot spring-batch


【解决方案1】:

尝试更新您的代码:

FlatFileItemWriter<Payments> writer = new FlatFileItemWriter<>();
        writer.setResource(new FileSystemResource("csv/outputs/users.processed" + fromId + "-" + toId + ".csv"));
        writer.setAppendAllowed(true);

收件人:

FlatFileItemWriter<Payments> writer = new FlatFileItemWriter<>();
        writer.setResource(new FileSystemResource("csv/outputs/users.processed" + fromId + "-" + toId + ".csv"));
        writer.setAppendAllowed(true);
        writer.setShouldDeleteIfEmpty(true);
        writer.setShouldDeleteIfExists(true);

我有同样的错误,它对我有用。

具体是因为FileUtils.setUpOutputFile(File file, boolean restarted, boolean append, boolean overwriteOutputFile)的restarted参数,在job重启时可以设置为true。文件从旧上下文中恢复并且不可写... 我不知道为什么。

【讨论】:

  • 无论我多么努力 - 如果 setAppendAllowed 设置为 false,我总是会收到此错误消息:org.springframework.batch.item.ItemStreamException:未创建输出文件。所以为了创建一个新文件,我必须这样做: PrintWriter pwriter;尝试 { pwriter = new PrintWriter(FILENAME); pwriter.print(""); pwriter.close(); } catch (FileNotFoundException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); }
【解决方案2】:

异常

if (!file.canWrite()) {
            throw new ItemStreamException("File is not writable: [" + file.getAbsolutePath() + "]");
}

File.canWrite 如下 所以请检查包括父母在内的路径,如果他们都有“写”权限

/**
 138:    * This method test whether or not the current thread is allowed to
 139:    * write to this object.  This will be true if and only if 1) The
 140:    * <code>SecurityManager</code> (if any) allows write access to the
 141:    * file and 2) The file exists and 3) The file is writable.  To determine
 142:    * whether or not a non-existent file can be created, check the parent
 143:    * directory for write access.
 144:    *
 145:    * @return <code>true</code> if writing is allowed, <code>false</code> 
 146:    * otherwise
 147:    *
 148:    * @exception SecurityException If the <code>SecurityManager</code> 
 149:    * does not allow access to the file
 150:    */
 151:   public boolean canWrite()
 152:   {
 153:     // First do a SecurityCheck before doing anything else.
 154:     checkWrite();
 155:      
 156:     // Test for existence.  This is required by the spec
 157:     if (! VMFile.exists(path))
 158:       return false;
 159: 
 160:     if (VMFile.isDirectory(path))
 161:       return VMFile.canWriteDirectory(this);
 162:     else
 163:       return VMFile.canWrite(path);
 164:   }

【讨论】:

  • 我和 Prateek 有同样的错误。您显示的代码与我的不同(请参阅source code)。 isInvalid() 似乎返回 true(请参阅 Source code)。我不知道为什么...
  • 好的,我找到了解决方案。有时会在作业重新启动时发生。我会发布一个答案...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-13
  • 2023-01-22
  • 2019-08-01
  • 1970-01-01
相关资源
最近更新 更多