Scala 在 while 循环中写入和读取文件

Scala writing and reading from a file inside a while loop

我有一个应用程序,我要将值写入文件并在 while 循环中将它们读回程序。这失败了,因为该文件仅在我退出循环时才写入,而不是在每次迭代中写入。因此,在接下来的迭代中,我无法访问应该在之前的迭代中写入文件的值。我怎样才能让每次迭代都写入文件而不是在 while 循环结束时写入所有值?

我的应用程序使用 Scalafix。它读入测试套件 Scala 文件并在每次迭代时复制其测试用例。我的 8 条评论系列解释了重要的细节。 FileWriter 的工作是否有一些东西让它等到循环的最后一轮才写回文件,因为它不会在循环的每次迭代中写回文件?

   object Printer{
          //1 . This is my filePrinter which I call at every iteration to print the new test file with its test cases duplicated.
          def saveFile(filename:String, data: String): Unit ={
            val fileWritter: FileWriter = new FileWriter(filename)
            val bufferWritter: BufferedWriter = new BufferedWriter(fileWritter)
            bufferWritter.write(data)
            bufferWritter.flush()
            bufferWritter.close()
         }
    }
    object Main extends App {
      //2. my loop starts here.
       var n = 2
     do {
       // read in a semanticDocument (function provided below)
       val ( sdoc1,base,filename)=SemanticDocumentBuilder.buildSemanticDocument()
       implicit val sdoc = sdoc1           //4. P3 is a scalafix "patch" that collects all the test cases of
        // test suite and duplicates them. It works just fine, see the next comment.
        val p3 =sdoc.tree.collect {
              case test@Term.ApplyInfix(Term.ApplyInfix(_,Term.Name(smc), _, 
                 List(Lit.String(_))), Term.Name("in"), _, params) =>
                 Patch.addRight(test,"\n" +test.toString())
              }.asPatch
        //5. I collect the test cases in the next line and print 
        //out how many they are. At this moment, I have not
       // applied the duplicate function, so they are still as 
       //originally read from the test file.
       val staticAnalyzer = new StaticAnalyzer()
       val testCases: List[Term.ApplyInfix] = 
       staticAnalyzer.collectTestCases()
       println("Tests cases count: "+ testCases.length)

       val r3 = RuleName(List(RuleIdentifier("r3")))
       val map:Map[RuleName, Patch] = Map(r3->p3)
       val r = PatchInternals(map, v0.RuleCtx(sdoc.tree), None)
      //6. After applying the p3 patch in the previous three lines, 
      //I indeed print out the newly created test suite file 
      //and it contains each test case  duplicated as shown
      // by the below println(r._1.getClass). 
       println(r._1.getClass)
       //7. I then call the my save file (see this function above - first lines of this code)

        Printer.saveFile(base+"src/test/scala/"+filename,r._1)

        n-=1
        //8. Since I have saved my file with the duplicates, 
        //I would expect that it will save the file back to the 
        //file (overwrite the original file as I have not used "append = true". 
        //I would then expect that the next length of test cases will 
        //have doubled but this is never the case. 
        //The save function with FileWriter only works in the last loop. 
       //Therefore, no matter the number of loops, it only doubles once!

        println("Loop: "+ n)
  } while(n>0)
}

**编辑排除了 semanticDocument ** 这个函数只是 returns 一个 SemanticDocument 和代表我的文件路径和文件名的两个字符串。

object SemanticDocumentBuilder{
def buildSemanticDocument(): (SemanticDocument,String,String) ={

val base  = "/Users/soft/Downloads/simpleAkkaProject/"                                     
val local = new File(base)                                                                 
//val dependenceisSBTCommand = s"sbt -ivy ./.ivy2 -Dsbt.ivy.home=./.ivy2 -Divy.home=./.ivy2
//val sbtCmd = s"sbt -ivy ./ivy2 -Dsbt.ivy.home=./ivy2 -Divy.home=./ivy2 -Dsbt.boot.directo
val result = sys.process.Process(Seq("sbt","semanticdb"), local).!                         
val jars = FileUtils.listFiles(local, Array("jar"), true).toArray(new Array[File](0))      
  .toList                                                                                  
  .map(f => Classpath(f.getAbsolutePath))                                                  
  .reduceOption(_ ++ _)                                                                    
val classes = FileUtils.listFilesAndDirs(local, TrueFileFilter.INSTANCE, DirectoryFileFilte
  .toList                                                                                  
  .filter(p => p.isDirectory && !p.getAbsolutePath.contains(".sbt") && p.getAbsolutePath.co
  .map(f => Classpath(f.getAbsolutePath))                                                  
  .reduceOption(_ ++ _)                                                                                                                                                            
val classPath = ClassLoader.getSystemClassLoader.asInstanceOf[URLClassLoader].getURLs      
  .map(url => Classpath(url.getFile))                                                      
  .reduceOption(_ ++ _)                                                                    
val all = (jars ++ classes ++ classPath).reduceOption(_ ++ _).getOrElse(Classpath(""))     
val symbolTable = GlobalSymbolTable(all)                                                   
val filename = "AkkaQuickstartSpec.scala"                                                  
val root = AbsolutePath(base).resolve("src/test/scala/")                                   
println(root)                                                                              
val abspath = root.resolve(filename)                                                       
println(root)                                                                              
val relpath = abspath.toRelative(AbsolutePath(base))                                       
println(relpath)                                                                           
val sourceFile = new File(base+"src/test/scala/"+filename)                                 
val input = Input.File(sourceFile)                                                         
println(input)                                                                             
if (n == firstRound){                                                                      
  doc = SyntacticDocument.fromInput(input)                                                 
}                                                                                          
//println(doc.tree.structure(30))                                                          
var documents: Map[String, TextDocument] = Map.empty                                       

Locator.apply(local.toPath)((path, db) => db.documents.foreach({                           
  case document@TextDocument(_, uri, text, md5, _, _, _, _, _) if !md5.isEmpty => { // skip
    if (n == firstRound){                                                                  
      ast= sourceFile.parse[Source].getOrElse(Source(List()))                              
    }                                                                                      
    documents = documents + (uri -> document)                                              
    println(uri)                                                                           
  }                                                                                        
   println(local.canWrite)                                                                 
    if (editedSuite != null){                                                              
      Printer.saveFile(sourceFile,editedSuite)                                             
    }                                                                                      
}))                                                                                        

//println(documents)                                                                       
val impl = new InternalSemanticDoc(doc, documents(relpath.toString()), symbolTable)        
implicit val sdoc = new SemanticDocument(impl)                                             
val symbols = sdoc.tree.collect {                                                          
  case t@ Term.Name("<") => {                                                              
    println(s"symbol for $t")                                                              
    println(t.symbol.value)                                                                
    println(symbolTable.info(t.symbol.value))                                              
  }                                                                                        
}                                                                                          
(sdoc,base,filename)
 }
}


saveFile 中,您需要在关闭 bufferedWriter 之后关闭 fileWriter。您不需要 flush,因为 close 会为您完成。


您还应该关闭在循环中创建的所有其他 File 对象,因为它们可能持有陈旧的文件句柄。 (例如 localast

更一般地说,通过将代码放入具有有意义名称的函数中来清理代码。还有很多代码可以在循环外。这样做将使您更容易看到正在发生的事情,并允许您创建 Minimal, Complete, and Verifiable example。就目前而言,真的很难弄清楚到底发生了什么。