Файлы Scala при чтении и записи блокируют проблемы

Описание проблемы

У меня есть приложение, в котором я должен записывать значения в файл и считывать их обратно в программу в цикле while. Это не удается, потому что файл записывается только при выходе из цикла, а не на каждой итерации. Поэтому в следующих итерациях я не могу получить доступ к значениям, которые должны были быть записаны в файл в предыдущих итерациях. Это приложение считывает тестовый файл из проекта scala и его зависимостей, затем редактирует его и записывает обратно в исходный файл. Редактирование итеративно в цикле. Я использую скалафикс и скаламета.

Мои файлы

После некоторых предыдущих размышлений мне пришло в голову, что у меня есть два файла: local и sourceFile. local содержит sourceFile. local — это каталог проекта Scala, а sourceFile — это файл .scala в подкаталоге test/scala/.

Описание кода

В методе main я получаю классы и jar-файлы из local и создаю синтаксический документ из sourceFile. Затем я выполняю редактирование с помощью SemanticDocument через патч-API ScalaFix. Наконец, я хочу записать отредактированную строку обратно в sourceFile, и это не удается, пока я не выйду из цикла (и, возможно, из JVM). Посмотрите комментарии к коду. Это похоже на проблему с блокировкой. Возможно, мои более ранние функции, которые искали банки, классы и semanticdb, не освобождали блокировки для sourceFile и local. Я проверил это, написав в другом файле за пределами local, и я получил ожидаемое поведение.

Вопрос

Как я могу заставить scala снять блокировку с этих файлов? Я попытался пройти через эти функции, и я все перепутал. Я не нашел способ освободить файлы. связанные с: Scala запись и чтение из файла внутри цикла while

package scalafix

import java.io.File
import java.net.URLClassLoader
import java.nio.file.Paths

import org.apache.commons.io.FileUtils
import org.apache.commons.io.filefilter.{DirectoryFileFilter, TrueFileFilter}
import scalafix.internal.patch.PatchInternals
import scalafix.internal.v1.InternalSemanticDoc
import scalafix.rule.RuleIdentifier
import scalafix.v1.{Patch, SemanticDocument, SyntacticDocument, _}
import scalafix.{Patch, RuleCtx, RuleName}

import scala.meta.Term.ApplyInfix
import scala.meta._
import scala.meta.inputs.Input
import scala.meta.internal.semanticdb.{Locator, TextDocument}
import scala.meta.internal.symtab.GlobalSymbolTable
import scala.meta.io.{AbsolutePath, Classpath}
import scala.meta.transversers.{SimpleTraverser, Transformer}
import scala.meta.{Name, Source}
import FileIO.enrichFile

import scala.sys.process._
import java.io.PrintWriter
import java.io.BufferedWriter
import java.io.FileWriter


object Printer{

//My function to write back to file
  def saveFile(filename: File, data: String): Unit ={
    val fileWritter: FileWriter = new FileWriter(filename)
    fileWritter.write(data)
    fileWritter.close()
  }
}

object Main extends App {
  //My variables to be updated after every loop
  var doc: SyntacticDocument = null
  var ast: Source = null
  var n = 3
  val firstRound = n
  var editedSuite:String = null
  do {
    val base  = "/Users/soft/Downloads/simpleAkkaProject/"
    // The local file
    val local = new File(base)
    // run an external command to compile source files in local into SemanticDocuments
    val result = sys.process.Process(Seq("sbt","semanticdb"), local).!
    // find jars in local.
    val jars = FileUtils.listFiles(local, Array("jar"), true).toArray(new Array[File](0))
      .toList
      .map(f => Classpath(f.getAbsolutePath))
      .reduceOption(_ ++ _)
    // find classes in local
    val classes = FileUtils.listFilesAndDirs(local, TrueFileFilter.INSTANCE, DirectoryFileFilter.DIRECTORY).toArray(new Array[File](0))
      .toList
      .filter(p => p.isDirectory && !p.getAbsolutePath.contains(".sbt") && p.getAbsolutePath.contains("target") && p.getAbsolutePath.contains("classes"))
      .map(f => Classpath(f.getAbsolutePath))
      .reduceOption(_ ++ _)
    // compute the classpath
    val classPath = ClassLoader.getSystemClassLoader.asInstanceOf[URLClassLoader].getURLs
      .map(url => Classpath(url.getFile))
      .reduceOption(_ ++ _)
    val all = (jars ++ classes ++ classPath).reduceOption(_ ++ _).getOrElse(Classpath(""))
    //combine classes, jars, and classpaths as dependencies into GlobalSymbolTable
    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)
    // The sourceFile
    val sourceFile = new File(base+"src/test/scala/"+filename)
   // use source file to compute a syntactic document
    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
    //use scalameta internalSemantic document to locate semantic documents in the local directory
    Locator.apply(local.toPath)((path, db) => db.documents.foreach({
      case document@TextDocument(_, uri, text, md5, _, _, _, _, _) if !md5.isEmpty => { // skip diagnostics files
        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)
        }
    }))

    //compute an implicit semantic document of the sourceFile for editing
   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))
      }
    }
    //edit the sourceFile semanticDocument
    val staticAnalyzer = new StaticAnalyzer()  
    val p3 = staticAnalyzer.duplicateTestCase()
    val r3 = RuleName(List(RuleIdentifier("r3")))
    val map:Map[RuleName, Patch] = Map(r3->p3)
    val r = PatchInternals(map, v0.RuleCtx(sdoc.tree), None)
    val parsed = r._1.parse[Source]
    ast = parsed.getOrElse(Source(List()))
    doc =SyntacticDocument.fromTree(parsed.get)
    val list: List[Int] = List()

    editedSuite = r._1
     println(local.canWrite)
    //Write back to the sourceFile for every loop. This works only when we exit!
    Printer.saveFile(sourceFile,r._1)
    println("Loop: "+ n)
    n-=1

  } while(n>0)

}


  [1]: https://stackoverflow.com/questions/54804642/scala-writing-and-reading-from-a-file-inside-a-while-loop

person Gakuo    schedule 25.02.2019    source источник


Ответы (1)


Вы пытались закрыть local и sourceFile в конце цикла? Вы действительно не можете быть уверены, что данные будут сброшены в файловую систему, пока файл все еще открыт.

Это также облегчит понимание, если вы переместите инварианты из цикла (кандидаты включают base, filename, root, abspath и, возможно, больше) и сгруппируете свой код в отдельные функции, чтобы вы могли видеть структуру вашего кода. более четко и сосредоточьтесь на тех частях, которые вызывают проблемы.

[Это повторение совета, который я дал в своем ответе на ваш предыдущий вопрос]

person Tim    schedule 25.02.2019