Skip to content

Instantly share code, notes, and snippets.

@unclebean
Last active November 5, 2024 09:46
Show Gist options
  • Select an option

  • Save unclebean/c7e831fb2496ce41a5139788b67516c1 to your computer and use it in GitHub Desktop.

Select an option

Save unclebean/c7e831fb2496ce41a5139788b67516c1 to your computer and use it in GitHub Desktop.
tiff2pdf_kotlin
import kotlinx.coroutines.*
import java.io.File
fun main() {
val tiffFiles = listOf("file1.tif", "file2.tif", "file3.tif") // List of TIFF file paths
val outputDir = "output/" // Directory where PDFs will be saved
runBlocking {
// Run each conversion in parallel using coroutines
val conversionJobs = tiffFiles.map { tiffFile ->
async {
convertTiffToPdf(tiffFile, outputDir)
}
}
// Wait for all conversions to complete
conversionJobs.awaitAll()
}
println("All TIFF files converted to PDF.")
}
// Function to convert a single TIFF file to PDF using a command-line tool
suspend fun convertTiffToPdf(tiffFilePath: String, outputDir: String) = withContext(Dispatchers.IO) {
val pdfFilePath = "$outputDir${File(tiffFilePath).nameWithoutExtension}.pdf"
val command = listOf("tiff2pdf", "-o", pdfFilePath, tiffFilePath) // Adjust the command if necessary
try {
val process = ProcessBuilder(command)
.redirectErrorStream(true)
.start()
// Wait for the command to finish
process.waitFor()
// Check if the conversion was successful
if (process.exitValue() == 0) {
println("Converted $tiffFilePath to $pdfFilePath")
} else {
println("Failed to convert $tiffFilePath")
}
} catch (e: Exception) {
println("Error converting $tiffFilePath: ${e.message}")
}
}
import java.io.File
fun main() {
val file = File("path/to/your/file.dat")
val regex = """checkSum":\s*"([^"]*)"""".toRegex()
file.forEachLine { line ->
val matchResult = regex.find(line)
if (matchResult != null) {
val checkSumValue = matchResult.groupValues[1]
println("Extracted checkSum value: $checkSumValue")
}
}
}
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardCopyOption
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
import java.util.zip.ZipOutputStream
object FileUtils {
// Function to create a directory
fun createDirectory(path: String): Boolean {
val dir = File(path)
return if (!dir.exists()) {
dir.mkdirs()
} else {
false
}
}
// Function to delete a directory recursively
fun deleteDirectory(path: String): Boolean {
val dir = File(path)
return if (dir.exists()) {
dir.deleteRecursively()
} else {
false
}
}
// Function to move a directory
fun moveDirectory(srcPath: String, destPath: String): Boolean {
val srcDir = Path.of(srcPath)
val destDir = Path.of(destPath)
return try {
Files.move(srcDir, destDir, StandardCopyOption.REPLACE_EXISTING)
true
} catch (e: Exception) {
e.printStackTrace()
false
}
}
// Function to zip a directory or file
fun zip(srcPath: String, destZipPath: String) {
val srcFile = File(srcPath)
ZipOutputStream(FileOutputStream(destZipPath)).use { zos ->
zipFile(srcFile, srcFile.name, zos)
}
}
private fun zipFile(fileToZip: File, fileName: String, zos: ZipOutputStream) {
if (fileToZip.isHidden) return
if (fileToZip.isDirectory) {
val children = fileToZip.listFiles()
children?.forEach { childFile ->
zipFile(childFile, "$fileName/${childFile.name}", zos)
}
return
}
FileInputStream(fileToZip).use { fis ->
val zipEntry = ZipEntry(fileName)
zos.putNextEntry(zipEntry)
fis.copyTo(zos)
}
}
// Function to unzip a zip file
fun unzip(zipFilePath: String, destDirPath: String) {
val destDir = File(destDirPath)
if (!destDir.exists()) destDir.mkdirs()
ZipInputStream(FileInputStream(zipFilePath)).use { zis ->
var entry: ZipEntry? = zis.nextEntry
while (entry != null) {
val newFile = File(destDir, entry.name)
if (entry.isDirectory) {
newFile.mkdirs()
} else {
File(newFile.parent).mkdirs()
FileOutputStream(newFile).use { fos ->
zis.copyTo(fos)
}
}
zis.closeEntry()
entry = zis.nextEntry
}
}
}
fun copyFileToBackup(sourcePath: String, backupFolderPath: String): Boolean {
return try {
// Create File objects from the paths
val sourceFile = File(sourcePath)
if (!sourceFile.exists()) {
println("Source file does not exist: $sourcePath")
return false
}
// Define the destination path in the backup folder
val destFile = File(backupFolderPath, sourceFile.name)
// Ensure the backup folder exists
destFile.parentFile?.mkdirs()
// Copy the file with REPLACE_EXISTING to overwrite if it already exists in the backup folder
Files.copy(sourceFile.toPath(), destFile.toPath(), StandardCopyOption.REPLACE_EXISTING)
println("File copied to backup successfully!")
true
} catch (e: Exception) {
e.printStackTrace() // Print any exceptions for debugging
false // Return false if an error occurs
}
}
fun findSingleZipFileWithId(directoryPath: String, id: String): File? {
val directory = File(directoryPath)
// Check if the directory exists and is indeed a directory
if (!directory.exists() || !directory.isDirectory) {
logError("Invalid directory path: $directoryPath")
return null
}
// Find zip files that contain the specified ID in their name
val matchingFiles = directory.listFiles { file ->
file.isFile && file.extension == "zip" && file.name.contains(id)
}
return when {
matchingFiles == null || matchingFiles.isEmpty() -> {
logError("No zip file found with ID: $id in directory: $directoryPath")
null
}
matchingFiles.size > 1 -> {
logError("Multiple zip files found with ID: $id in directory: $directoryPath. Only one file expected.")
null
}
else -> matchingFiles[0] // Return the single matching file
}
}
fun zipFolderContents(sourceDirPath: String, zipFilePath: String) {
val sourceDir = File(sourceDirPath)
val zipFile = File(zipFilePath)
FileOutputStream(zipFile).use { fos ->
ZipOutputStream(fos).use { zos ->
sourceDir.listFiles()?.forEach { file ->
zipFileOrDirectory(file, "", zos)
}
}
}
}
fun zipFileOrDirectory(file: File, parentPath: String, zos: ZipOutputStream) {
val entryName = if (parentPath.isEmpty()) file.name else "$parentPath/${file.name}"
if (file.isDirectory) {
file.listFiles()?.forEach { childFile ->
zipFileOrDirectory(childFile, entryName, zos)
}
} else {
FileInputStream(file).use { fis ->
val zipEntry = ZipEntry(entryName)
zos.putNextEntry(zipEntry)
fis.copyTo(zos)
zos.closeEntry()
}
}
}
}
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<version>9.16.0</version> <!-- Use the latest version -->
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.6.0</version> <!-- Use the latest version -->
</dependency>
fun calculateMD5Checksum(filePath: String): String? {
val processBuilder = ProcessBuilder("md5sum", filePath)
processBuilder.redirectErrorStream(true)
val process = processBuilder.start()
// Read the output of the command
val reader = BufferedReader(InputStreamReader(process.inputStream))
val output = reader.readLine()
reader.close()
// Wait for the process to finish
process.waitFor()
// Extract and return the checksum value (first part of the output)
return output?.split(" ")?.firstOrNull()
}
<configuration>
<property name="LOG_FILE" value="${log.file:-default.log}"/>
<!-- Service Log Appender -->
<appender name="SERVICE_LOG" class="ch.qos.logback.core.FileAppender">
<file>${LOG_FILE}/service.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- Audit Log Appender -->
<appender name="AUDIT_LOG" class="ch.qos.logback.core.FileAppender">
<file>${LOG_FILE}/audit.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- Root Logger for general application logging -->
<root level="INFO">
<appender-ref ref="SERVICE_LOG"/>
</root>
<!-- Separate Logger for Audit functionality -->
<logger name="com.yourpackage.audit" level="INFO" additivity="false">
<appender-ref ref="AUDIT_LOG"/>
</logger>
</configuration>
fun main(args: Array<String>) {
// Expecting the path to the properties file as the first command-line argument
if (args.isEmpty()) {
println("Please provide the path to the properties file.")
return
}
val propertiesFilePath = args[0]
val properties = loadProperties(propertiesFilePath)
// Access individual properties
val inputFilePath = properties.getProperty("inputFilePath") ?: throw IllegalArgumentException("inputFilePath not found")
val outputDirectory = properties.getProperty("outputDirectory") ?: throw IllegalArgumentException("outputDirectory not found")
val logLevel = properties.getProperty("logLevel") ?: "INFO" // Default to INFO if not set
val timeout = properties.getProperty("timeout")?.toIntOrNull() ?: 60 // Default to 60 if not set or invalid
// Use the properties in your tool
println("Input File Path: $inputFilePath")
println("Output Directory: $outputDirectory")
println("Log Level: $logLevel")
println("Timeout: $timeout")
}
<dependency>
<groupId>io.github.microutils</groupId>
<artifactId>kotlin-logging-jvm</artifactId>
<version>3.0.5</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.5</version>
</dependency>
<dependency>
<groupId>com.github.doyaaaaaken</groupId>
<artifactId>kotlin-csv-jvm</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-coroutines-core</artifactId>
<version>1.6.4</version>
</dependency>
<project>
<!-- Your existing project configuration -->
<build>
<plugins>
<!-- Maven Shade Plugin for creating a fat JAR -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<transformers>
<!-- Set the main class in the manifest -->
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>MainKt</mainClass> <!-- Replace with your actual main class path -->
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
import com.github.doyaaaaaken.kotlincsv.dsl.csvReader
import java.io.File
data class CsvEntry(val parentZip: String, val count: Int, val tifFiles: List<String>)
fun readCsv(filePath: String): List<CsvEntry> {
val rows = csvReader().readAllWithHeader(File(filePath))
return rows.map { row ->
val parentZip = row["parent_zip"] ?: ""
val count = row["count"]?.toIntOrNull() ?: 0
val tifFiles = row["tif_files"]?.split(",")?.map { it.trim() } ?: emptyList()
CsvEntry(parentZip, count, tifFiles)
}
}
fun main(args: Array<String>) {
if (args.isEmpty()) {
println("Please provide the path to the CSV file as a command-line argument.")
return
}
val filePath = args[0]
if (!File(filePath).exists()) {
println("The file at path '$filePath' does not exist.")
return
}
val entries = readCsv(filePath)
entries.forEach { entry ->
println("Parent Zip: ${entry.parentZip}, Count: ${entry.count}, TIF Files: ${entry.tifFiles}")
}
}
import java.io.FileInputStream
import java.util.Properties
fun loadProperties(filePath: String): Properties {
val properties = Properties()
FileInputStream(filePath).use { inputStream ->
properties.load(inputStream)
}
return properties
}
fun parseCsvColumnToList(input: String): List<Int> {
// Remove any surrounding quotes and brackets
val trimmedInput = input.trim().removeSurrounding("[", "]").removeSurrounding("\"")
// Split by commas and map to integers, logging conversion failures
return trimmedInput.split(",").mapNotNull { element ->
try {
element.trim().toInt()
} catch (e: NumberFormatException) {
logger.error("Failed to convert '$element' to Int", e)
null
}
}
}
import kotlinx.coroutines.*
import mu.KotlinLogging
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.nio.file.Files
import java.security.MessageDigest
import java.util.concurrent.Executors
import java.util.zip.ZipEntry
import java.util.zip.ZipFile
import java.util.zip.ZipOutputStream
import kotlin.io.path.ExperimentalPathApi
import kotlin.io.path.createTempDirectory
import kotlin.io.path.deleteRecursively
private val logger = KotlinLogging.logger {}
@OptIn(ExperimentalPathApi::class)
fun main() {
val csvFiles = listOf("path/to/csv1.csv", "path/to/csv2.csv") // Add paths to your CSV files here
val executor = Executors.newFixedThreadPool(csvFiles.size) // Create a thread for each CSV file
csvFiles.forEach { csvFile ->
executor.submit {
runBlocking {
processCsvFile(csvFile)
}
}
}
executor.shutdown()
}
suspend fun processCsvFile(csvFilePath: String) = coroutineScope {
logger.info { "Processing CSV file: $csvFilePath" }
val tempDir = createTempDirectory("zipProcessing_${File(csvFilePath).nameWithoutExtension}")
try {
val entries = parseCsvFile(csvFilePath) // Parse CSV for zip and TIFF file paths
val zipJobs = entries.map { entry ->
async {
processZipEntry(entry.zipFilePath, entry.tiffFiles, tempDir)
}
}
zipJobs.awaitAll() // Wait for all zip files for this CSV to complete
} finally {
tempDir.deleteRecursively()
logger.info { "Cleaned up temporary directory for CSV: $csvFilePath" }
}
}
suspend fun processZipEntry(zipFilePath: String, tiffFiles: List<String>, tempDir: java.nio.file.Path) = coroutineScope {
logger.info { "Processing zip file: $zipFilePath" }
val zipDir = Files.createTempDirectory(tempDir, "zip_${File(zipFilePath).nameWithoutExtension}")
unzip(File(zipFilePath), zipDir.toFile())
val convertJobs = tiffFiles.map { tiffFile ->
async {
val tiffPath = zipDir.resolve(tiffFile).toFile()
val pdfFile = File(tiffPath.parent, "${tiffPath.nameWithoutExtension}.pdf")
convertTiffToPdf(tiffPath, pdfFile)
tiffPath.delete()
logger.info { "Converted and replaced TIFF file: ${tiffFile.name}" }
}
}
convertJobs.awaitAll() // Wait for all conversions in this zip to complete
val modifiedZip = File(tempDir.toFile(), File(zipFilePath).name)
zipDirectory(zipDir.toFile(), modifiedZip)
logger.info { "Recreated modified zip: ${modifiedZip.absolutePath}" }
zipDir.deleteRecursively()
logger.info { "Cleaned up temporary extraction directory for zip: $zipFilePath" }
}
fun unzip(zipFile: File, destDir: File) { /* Same as before */ }
suspend fun convertTiffToPdf(tiffFile: File, pdfFile: File) = withContext(Dispatchers.IO) { /* Same as before */ }
fun zipDirectory(sourceDir: File, zipFile: File) { /* Same as before */ }
fun calculateChecksum(file: File): String { /* Same as before */ }
fun parseCsvFile(csvFilePath: String): List<ZipEntryData> { /* Parse CSV to retrieve file paths */ }
data class ZipEntryData(val zipFilePath: String, val tiffFiles: List<String>)
fun updateCheckSum(filePath: String, newCheckSum: String) {
val file = File(filePath)
val regex = """("checkSum":\s*")([^"]*)(")""".toRegex()
// Read the entire content of the file
val content = file.readText()
// Replace the old checksum value with the new one
val updatedContent = regex.replace(content) {
// it.groupValues[1] captures "checkSum": "
// it.groupValues[3] captures the trailing quote after the old checksum value
"${it.groupValues[1]}$newCheckSum${it.groupValues[3]}"
}
// Write the updated content back to the file
file.writeText(updatedContent)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment