I have a python socket server that sends a PNG file (72755 bytes) whenever receives "send" from the client. The client python code receives 72755 bytes and saves the file correctly:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
s.send('send')
f = open('torecv.png','wb')
l = s.recv(1024)
while (l):
f.write(l)
l = s.recv(1024)
k = str(l)
byte_num += len(l)
if k[-5:-1] == 'done':
break
f.write(l[:-4])
f.close()
s.close()
However, in Swift, the following code gets a total of 72755 bytes and gives me a corrupted PNG file. Can anyone tell me where is the problem? Thank you
switch client.connect(timeout: 1) {
case .success:
switch client.send(string: "send" ) {
case .success:
var dataAll : [UInt8] = []
while true {
guard let data = client.read(1024, timeout:1) else { break }
print("bytes: " + String(data.count))
if String(bytes: data, encoding: .utf8) == "done" {
print("done")
}else{
dataAll += data
}
}
print(dataAll.count) // prints 72755
let img : Data = Data(bytes: dataAll, count: dataAll.count)
writeToFile(data: img, fileName: "testPng")
Edit:
The problem could be in saving PNG file (Both Python and Swift get all bytes correctly)
func writeToFile(data: Data, fileName: String){
// get path of directory
guard let directory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last else {
return
}
// create file url
let fileurl = directory.appendingPathComponent("\(fileName).png")
print(fileurl)
// if file exists then write data
if FileManager.default.fileExists(atPath: fileurl.path) {
if let fileHandle = FileHandle(forWritingAtPath: fileurl.path) {
// seekToEndOfFile, writes data at the last of file(appends not override)
fileHandle.seekToEndOfFile()
fileHandle.write(data)
fileHandle.closeFile()
var yourImage: UIImage = UIImage(named: fileurl.path)!
testImg.image = yourImage
}
else {
print("Can't open file to write.")
}
}
else {
// if file does not exist write data for the first time
do{
try data.write(to: fileurl, options: .atomic)
}catch {
print("Unable to write in new file.")
}
}
}
Main Image and what Python gets:
What Swift gets:
Related
I am concatenating images into a video using mobileffmpeg cocoapod using the command below but the video quality drops a bit when it has finished concatenating.
-f concat -i \(outputTxt) -b:v 8M -pattern_type sequence -r 25 \(output)
I can see the image array isn't the issue as the quality is good so how can I avoid losing quality when concatenating? I thought maybe using libx264 would solve the issue but it isn't supported by mobileffmpeg
Below are the functions I use in Swift to concatenate if it helps understand the process.
Thanks for your help!
func concatonateScreenshotsToVideo( completed: #escaping (URL) -> ()){
if compilingVideo {
self.delegate?.screenRecordingConcatonating()
var imgs = self.storedTempScreenshotImgArray()
imgs.sort()
self.createFFmpegTextFile(tempScreenshotImgArray: imgs) {
let filename = "screenshot_ffmpegData.txt"
let outputTxt = URL(fileURLWithPath: self.mainPath + "/Temp/").appendingPathComponent(filename)
let output = URL(fileURLWithPath: self.mainPath + "/Temp/").appendingPathComponent("screenshot.mp4")
let ffmpeg = "-f concat -i \(outputTxt) -b:v 8M -pattern_type sequence -r \(self.fps) \(output)"
MobileFFmpeg.execute(ffmpeg)
completed(output)
}
} else {
terminateFFmpeg()
return
}
}
func createFFmpegTextFile(tempScreenshotImgArray: [String], completed: () -> Void){
let filename = "screenshot_ffmpegData.txt"
let textFile = URL(fileURLWithPath: mainPath).appendingPathComponent("Temp/\(filename)")
for img in tempScreenshotImgArray {
autoreleasepool {
do {
let fileHandle = try FileHandle(forWritingTo: textFile)
fileHandle.seekToEndOfFile()
let filepath = "file \(img)\n duration 0.04\n"
fileHandle.write(filepath.data(using: .utf8)!)
} catch {
do {
let filePath = "file \(img)\n duration 0.04\n"
try filePath.write(to: textFile, atomically: false, encoding: .utf8)
} catch {
DebugPrint.DBprint("FFmpeg manager error writing text file: \(error.localizedDescription)")
}
}
}
}
func storedTempScreenshotImgArray() -> [String] {
var screenshotImgArray: [String] = []
guard let dataFilePath = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent("/Temp") else {return screenshotImgArray}
do {
let fileUrls = try fileManager.contentsOfDirectory(at: dataFilePath, includingPropertiesForKeys: nil)
for jpgFile in fileUrls {
if jpgFile.pathExtension == "jpg" && !screenshotImgArray.contains(jpgFile.lastPathComponent) {
screenshotImgArray.append(jpgFile.lastPathComponent)
}
}
} catch {
DebugPrint.DBprint("screenshot - Error while enumerating folder segment")
}
return screenshotImgArray
}
use :
pod 'mobile-ffmpeg-full-gpl'
that support's x264 and x265
in here you can read about mobile ffmpeg versions
for using in swift you should add ProjectName-Bridging-Header.h to your project and then import the library in that: #import <mobileffmpeg/MobileFFmpeg.h>
I'm trying to get some content from a .txt file by doing
let ruterQuery = loadR(filename: "content.txt")
func loadR( filename: String ) -> String {
let data: Data
guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
else {
fatalError("Couldn't find \(filename) in main bundle.")
}
do {
data = try Data(contentsOf: file)
} catch {
fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
}
print(data)
return "done"
}
But when I print the data it only says "2045 bytes", how do I get the actual content of the file?
This is the content.txt, it's for an api url as a "query" of what fields to be returned. So the url will be "https://api.myapi.com/planner?query=" + content.txt
"{\n\tplaces(\n\t\tids:[\"ABC:StopPlace:8329\", \"ABC:StopPlace:0808\"]\n\t) {\n\t\tname\n\t\tid\n\t\testimatedCalls(timeRange: 72100, numberOfDepartures: 20) {\n\n\t\t\trealtime\n\t\t\trealtimeState\n\t\t\texpectedDepartureTime\n\t\t\tpredictionInaccurate\n\t\t\tdestinationDisplay {\n\t\t\t\tfrontText\n\t\t\t}\n\t\t\tquay {\n\t\t\t\tid\n\t\t\t}\n\n\t\t\tsituations {\n\t\t\t\tid\n\t\t\t\tlines {\n\t\t\t\t\tid\n\t\t\t\t}\n\t\t\t\tsummary {\n\t\t\t\t\tvalue\n\t\t\t\t\tlanguage\n\t\t\t\t}\n\t\t\t\tstopPlaces {\n\t\t\t\t\tid\n\t\t\t\t}\n\t\t\t\tdescription {\n\t\t\t\t\tvalue\n\t\t\t\t\tlanguage\n\t\t\t\t}\n\t\t\t\tvalidityPeriod {\n\t\t\t\t\tstartTime\n\t\t\t\t\tendTime\n\t\t\t\t}\n\t\t\t\tseverity\n\t\t\t\tsituationNumber\n\t\t\t}\n\n\t\t\tserviceJourney {\n\t\t\t\tid\n\t\t\t\tpublicCode\n\t\t\t\tprivateCode\n\t\t\t\tserviceAlteration\n\t\t\t\ttransportSubmode\n\t\t\t\tdirectionType\n\n\t\t\t\tnotices {\n\t\t\t\t\tid\n\t\t\t\t\ttext\n\t\t\t\t\tpublicCode\n\t\t\t\t}\n\n\t\t\t\tjourneyPattern {\n\t\t\t\t\tid\n\t\t\t\t\tline{\n\t\t\t\t\t\tid\n\t\t\t\t\t\tname\n\t\t\t\t\t\tpublicCode\n\t\t\t\t\t\ttransportMode\n\t\t\t\t\t\ttransportSubmode\n\t\t\t\t\t\tpresentation {\n\t\t\t\t\t\t\ttextColour\n\t\t\t\t\t\t\tcolour\n\t\t\t\t\t\t}\n\t\t\t\t\t\tsituations {\n\t\t\t\t\t\t\tid\n\t\t\t\t\t\t\tdescription {\n\t\t\t\t\t\t\t\tvalue\n\t\t\t\t\t\t\t\tlanguage\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tvalidityPeriod {\n\t\t\t\t\t\t\t\tstartTime\n\t\t\t\t\t\t\t\tendTime\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tsituations {\n\t\t\t\t\tid\n\t\t\t\t\tlines {\n\t\t\t\t\t\tid\n\t\t\t\t\t}\n\t\t\t\t\tsummary {\n\t\t\t\t\t\tvalue\n\t\t\t\t\t\tlanguage\n\t\t\t\t\t}\n\t\t\t\t\tstopPlaces {\n\t\t\t\t\t\tid\n\t\t\t\t\t}\n\t\t\t\t\tdescription {\n\t\t\t\t\t\tvalue\n\t\t\t\t\t\tlanguage\n\t\t\t\t\t}\n\t\t\t\t\tvalidityPeriod {\n\t\t\t\t\t\tstartTime\n\t\t\t\t\t\tendTime\n\t\t\t\t\t}\n\t\t\t\t\tseverity\n\t\t\t\t\tsituationNumber\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t}\n}\n"
The content of the file is JSON rather than simply text.
You get the the string representation with
func loadR(filename: String ) -> String {
let url = Bundle.main.url(forResource: filename, withExtension: "txt")!
let data = try! Data(contentsOf: url)
let string = String(data: data, encoding: .utf8)!
print(string)
return string
}
If the code crashes you made a design mistake. As files in the bundle are immutable at runtime the code must not crash.
Another bad practice are all the unnecessary whitespace characters. Unlike a human being the device doesn't care about prettyPrinting
I have the following code which writes to the end of a file. However, how do I modify the behaviour so that it creates "output.txt" if it doesn't exist?
Thanks in advance!
func writeFile(){
let str = "\n" + nominationKeyForWhenCellSelected! + "," + "1"
let datafromString = str.data(using: String.Encoding.utf8)
let filename = getDocumentsDirectory().appendingPathComponent("output.txt")
do {
let fileHandle = try FileHandle(forWritingTo: filename)
fileHandle.seekToEndOfFile()
fileHandle.write(datafromString!)
} catch {
}
}
Use FileManager to check if the file exists or not. If not, simply write the data, otherwise append as you are doing. But don't forget to close the file handle.
do {
if FileManager.default.fileExists(atPath: filename.path) {
let fileHandle = try FileHandle(forWritingTo: filename)
fileHandle.seekToEndOfFile()
fileHandle.write(datafromString!)
fileHandle.closeFile()
} else {
datafromString.write(to: filename)
}
} catch {
print(error)
}
I’m trying to get String from txt file inside the zip file using native libcompression library. Actually I use the code from
https://github.com/mw99/DataCompression/blob/master/Sources/DataCompression.swift.
At first, I was doing:
let zip = try? Data(contentsOf: "/.../test.zip")
let tmp: Data? = zip?.unzip()
let txt: String? = String(data: tmp!, encoding: .utf8)
But how do I get the contents of zip file and how do I get data from certain txt file?
ZIP Foundation supports accessing individual entries in ZIP archives.
You have to initialize an archive by passing a file URL to the Archive initializer.
Afterwards you can access a specific entry via subscripting:
let fileManager = FileManager()
let currentWorkingPath = fileManager.currentDirectoryPath
var archiveURL = URL(fileURLWithPath: currentWorkingPath)
archiveURL.appendPathComponent("test.zip")
guard let archive = Archive(url: archiveURL, accessMode: .read) else {
return
}
guard let entry = archive["file.txt"] else {
return
}
var destinationURL = URL(fileURLWithPath: currentWorkingPath)
destinationURL.appendPathComponent("out.txt")
do {
try archive.extract(entry, to: destinationURL)
} catch {
print("Extracting entry from archive failed with error:\(error)")
}
You can also directly access the contents of entry by using the closure based API. This allows you to process the entry without writing it to the file system first:
try archive.extract(entry, consumer: { (data) in
print(data.count)
})
I am using my phone to record some sensor data and store it on device via SQLite via SharkORM(DBAccess).
I now want to write that data out to a CSV file however, I am now up to 1.6 million records.
Currently, I am looping through 1000 records, adding them to a string and at the end writing them out. However, there must be a better way to do it?
func writeRawFile()
{
let fileName = "raw"
let DocumentDirURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let fileURL = DocumentDirURL.appendingPathComponent(fileName).appendingPathExtension("csv")
var data = "time,lat,lon,speed,x_acc,y_acc,z_acc,gyro_x,gyro_y,gyro_z,compass,orientation\r\n"
let count = RawReading.query().count()
var counter = 0;
let df = DateFormatter()
df.dateFormat = "y-MM-dd H:m:ss.SSSS"
for i in stride(from:0, to: count, by: 1000)
{
autoreleasepool {
for result in RawReading.query().offset(Int32(i)).limit(1000).fetch()
{
if let raw : RawReading = result as? RawReading
{
if (Double(raw.speed!) > 3.0) //1 Meter per Second = 2.236936 Miles per Hour
{
//print(df.string(from: raw.date!))
data += "\(df.string(from: raw.date!)),\(raw.lat!),\(raw.lon!),\(raw.speed!),\(raw.x!),\(raw.y!),\(raw.z!),\(raw.xx!),\(raw.yy!),\(raw.zz!),\(raw.compass!),\(raw.orientation!)" + "\r\n"
counter += 1
}
}
}
print ("Written \(i) of \(count)")
}
}
print("Count \(count) \(counter)")
//write the file, return true if it works, false otherwise.
do{
try data.write(to: fileURL, atomically: true, encoding: String.Encoding.utf8 )
} catch{
print("error")
}
}
Open a FileHandle for writing, then build and write each line separately, so that you don't have to keep the entire file contents
in memory:
do {
let file = try FileHandle(forWritingTo: fileURL)
defer { file.closeFile() }
for <... your loop ...> {
let line = ... // build one CSV line
file.write(line.data(using: .utf8)!)
}
} catch let error {
// ...
}
You can also write to a temporary file first and then rename it to the
actual file, in order to avoid a damaged file if anything
went wrong.