I'm new in kotlin. I'm trying to read file line by line and add something at the end to each of them.
My file before reading:
abcd;abcd;abcd;
bcda;bcda;bcda;
dacb;dacb;dacb;
My file after reading and appending:
abcd;abcd;abcd;smth1
bcda;bcda;bcda;smth2
dacb;dacb;dacb;smth3
I have code for reading file line by line but could you tell me how to add string to each of them?
val pathToFile = "abc.txt"
val scan = Scanner(File(pathToFile))
while (scan.hasNextLine()) {
val line = scan.nextLine()
var lista = ArrayList<String>()
lista = line.split(";") as ArrayList<String>
println(lista.get(0) + " and " + lista.get(1) + " and " + lista.get(2))
}
Januson has the right idea. Here is some Kotlin code to do the job:
inline fun File.mapLines(crossinline transform: (line: String) -> String) {
val tempFile = createTempFile(prefix = "transform", suffix = ".txt")
tempFile.printWriter().use { writer ->
this.forEachLine { line -> writer.println(transform(line)) }
}
check(this.delete() && tempFile.renameTo(this)) { "failed to replace file" }
}
Example usage:
val pathToFile = "abc.txt"
var index = 0
File(pathToFile).mapLines { line -> "${line}smth${++index}" }
If you are using Java 1.7+ then you can use Files.move instead of delete/renameTo:
Files.move(tempFile.toPath(), this.toPath(), StandardCopyOption.REPLACE_EXISTING)
See also Write to file after match in Kotlin.
You can't read and write to the same file unless you are using RandomAccessFile. Instead you should do the following:
Read line from your input file.
Do the modification you want (append to the end of the line, print line).
Write modified line to the output file.
After reading/writing all the data close both files.
Delete input file. Rename output file to the input file name.
Related
I have a simple snippet of Kotlin code
import java.io.*
import java.util.concurrent.TimeUnit.MINUTES
import java.util.concurrent.TimeUnit
val proc = ProcessBuilder("C:\\tools\\build\\maven\\3.6.1\\bin\\mvn.cmd")
.directory(null)
.redirectOutput(ProcessBuilder.Redirect.PIPE)
.redirectError(ProcessBuilder.Redirect.PIPE)
.start()
println("Started")
proc.waitFor(60, TimeUnit.MINUTES)
println("Ended")
val output : String = proc.inputStream.bufferedReader().readText()
println("Output : " + output)
var log : File = File("cmd.log")
log.writeText(output)
This code run command then saves output in string then print output to console
But printing is occured when external program is completed.
My question is:
I would like to see program output in real time mode.
From other hands I would like to see output of external program while it works.
This code run as Kotlin script : kotlinc -script script.ktc
If place string
val output : String = proc.inputStream.bufferedReader().readText()
Before waitFor call. I observed that execution is blocked as expected
I'm sorry for this question, it was quite simple,I found simple answer today.
val proc = ProcessBuilder("ls", "-lR", "c:\\toolchains")
.directory(null)
.redirectOutput(ProcessBuilder.Redirect.PIPE)
.redirectError(ProcessBuilder.Redirect.PIPE)
.start()
println("Started")
val output: BufferedReader = proc.inputStream.bufferedReader()
var line: String? = output.readLine()
val log: File = File("cmd.log")
while (line != null) {
println("Next Line " + line)
log.appendText(line.toString() + System.lineSeparator())
line = output.readLine()
}
proc.waitFor(60, TimeUnit.MINUTES)
println("Ended")
I'm very new to Kotlin and making a command line .exe, on Windows using Kotlin/Native. The application should read from a text file and print on screen, line by line. When it reaches the last line of the file, it should put it in the clipboard.
aFile.txt looks something like this:
one
two
three
...
...
the last line
and the code read.kt (Kotlin/Native) I have so far is this:
import kotlinx.cinterop.*
import platform.posix.*
fun main(args: Array<String>) {
if (args.size != 1) {
println("Usage: read.exe <file.txt>")
return
}
val fileName = args[0]
val file = fopen(fileName, "r")
if (file == null) {
perror("cannot open input file $fileName")
return
}
try {
memScoped {
val bufferLength = 64 * 1024
val buffer = allocArray<ByteVar>(bufferLength)
do {
val nextLine = fgets(buffer, bufferLength, file)?.toKString()
if (nextLine == null || nextLine.isEmpty()) break
print("${nextLine}")
} while (true)
}
} finally {
fclose(file)
}
}
The code above prints each line on the screen, but how do I write the string "the last line" in the computer's clipboard? I'm looking for a native (not Java) solution if that's possible.
Thank you very much.
Update:
Obviously, this is not the solution I was looking for, but I don't understand yet what are they talking about here (https://learn.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-setclipboarddata).
As a temporary fix, I was able to get what I needed using system(), echo and clip with code like this:
system("echo ${nextLine} | clip")
print("${nextLine}")
Try the following:
import java.awt.Toolkit
import java.awt.datatransfer.Clipboard
import java.awt.datatransfer.StringSelection
fun setClipboard(s: String) {
val selection = StringSelection(s)
val clipboard: Clipboard = Toolkit.getDefaultToolkit().systemClipboard
clipboard.setContents(selection, selection)
}
In Windows, you can work with the Clipboard through WinAPI, as you can see there. The reference says, that you got to use functions from the winuser.h header. This header is included in windows.h, as far as I know, so it is in your platform.windows.* package. You can approve it by checking Kotlin/Native repository files.
To clarify, what I meant, I wrote this small example of platform.windows.* usage. You can add this function to your code, and call it when you got to copy some string.
import platform.windows.*
fun toClipboard(lastLine:String?){
val len = lastLine!!.length + 1
val hMem = GlobalAlloc(GMEM_MOVEABLE, len.toULong())
memcpy(GlobalLock(hMem), lastLine.cstr, len.toULong())
GlobalUnlock(hMem)
val hwnd = HWND_TOP
OpenClipboard(hwnd)
EmptyClipboard()
SetClipboardData(CF_TEXT, hMem)
CloseClipboard()
}
I use the PDFBox function, such as convertToImage, everything works fine, but PDFBox does not clear the temporary files after the conversion. In my system in the directory for temporary files "/tmp" there are many files such us +~JF132216249314633400.tmp, they are deleted only after restarting my application, but when the application continues to work, temporary files are not deleted.
PDFBox version - 1.8.15
when I use this
page.convertToImage(BufferedImage.TYPE_INT_RGB, 300)
the PDFbox library creates tmp files such as "+~JF132216249314633400.tmp"
my method:
def splitPdfToImages(file: File): List[File] = {
val document = PDDocument.load(file)
val pages = (for (i <- 0 until document.getNumberOfPages)
yield document.getDocumentCatalog.getAllPages.get(i).asInstanceOf[PDPage]).toList
val imgFiles = pages.zipWithIndex.map { case (page, i) =>
val baos = IOUtils.createBAOS
ImageIO.write(page.convertToImage(BufferedImage.TYPE_INT_RGB, 300), "jpg", baos)
val bais = IOUtils.createBAIS(baos.toByteArray)
try {
val img = Image.fromStream(bais)
implicit val writer = JpegWriter().withCompression(100)
val tmpFile = File.createTempFile(s"""${file.getName.split("\\.").head}_$i""", file.getName.split("\\.").last)
img.output(tmpFile)
} finally {
baos.close()
bais.close()
}
}
document.close()
imgFiles
}
Please help me to solve this issue.
I've been using this script to load values separated by new line from files to send requests with different values.
def size
File valueFile = new File("C:\\values\\myValueFile.txt")
File valueFile2 = new File("C:\\values\\myValueFile2.txt")
List lines = valueFile.readLines()
List lines2 = valueFile2.readLines()
size = lines.size.toInteger()
def myProps = testRunner.testCase.getTestStepByName("MyProperties")
for( counter in 0..size-1)
{
tempValue = lines[counter]
tempValue2 = lines2[counter]
myProps.setPropertyValue("Value", tempValue)
myProps.setPropertyValue("Value2", tempValue2)
log.info tempValue
log.info tempValue2
testRunner.runTestStepByName("updateBusinessTrip")
}
How to make it load values from same file separated by ";"?
txt file would look like that:
Value1;Value2
Value1.1;Value2.1
Value1.2;Value2.2
If I got you...:
Option 1:
tempValue = lines[counter].split(/;/)
myProps.setPropertyValue("Value", tempValues[0])
myProps.setPropertyValue("Value2", tempValue[1])
or Option 2:
(tempValue, tempValue2) = lines[counter].tokenize(';')
myProps.setPropertyValue("Value", tempValues)
myProps.setPropertyValue("Value2", tempValue2)
or another one:
File valueFile = new File("C:\\values\\myValueFile.txt")
def myProps = testRunner.testCase.getTestStepByName("MyProperties")
valueFile.splitEachLine(/;/) { items ->
myProps.setPropertyValue("Value", items[0])
myProps.setPropertyValue("Value2", items[1])
log.info tempValue
log.info tempValue2
testRunner.runTestStepByName("updateBusinessTrip")
}
I read a file encoded in Windows-1250. I read each line into a list, then do some append operations and store the collection into a new file.
Problem. If I write explicitly encoding, then the output file appear to be badly encoded. If I do not set any encoding, output is OK.
enrichedFile.withWriter("windows-1250") { out ->
tempFinalList.each() { line ->
out.println line
}
}
=> bad output
enrichedFile.withWriter { out ->
tempFinalList.each() { line ->
out.println line
}
}
=> OK.
FYI: I use it for czech language with letters as: ěščřžýáíé.
I do not see there is any problem.
def myFile = new File('./Archive/file.txt')
def tempFinalList = []
//Reading from the file with windows charset
myFile.withReader('windows-1250') { out ->
out.eachLine{
tempFinalList << it
}
}
//Appending stuff
tempFinalList << 'a' << 'b'
//Creating a new file
def newFile = new File('./Archive/NewFile.txt')
//Writing to the new file with windows charset
newFile.withWriter('windows-1250'){out ->
tempFinalList.each{out.writeLine it}
}
newFile.eachLine{println it}
Where content of file.txt contains czech characters you have mentioned.
Output from the last line:
ešcržýáíé
ešcržýáíé
ešcržýáíé
ešcržýáíé
ešcržýáíé
a
b