diff --git a/Sources/CSVExport.swift b/Sources/CSVExport.swift index 1ad7141..7f0a919 100644 --- a/Sources/CSVExport.swift +++ b/Sources/CSVExport.swift @@ -237,6 +237,22 @@ public func exportCSV(_ filename:String, fields: [String], values: NSArray) -> S return CSVExport.export.exportCSV(filename, fields: fields as NSArray, values: values); } +///a free function to make export the CSV file from file name, fields and values +public func exportCSV(_ filename:String, fields: [String], values: [[String:Any]]) -> String{ + // Convert [String:Any] to NSDictionary + let data:NSMutableArray = NSMutableArray() + for dict in values { + let row:NSMutableDictionary = NSMutableDictionary() + for i in 0 ..< fields.count { + row.setValue((dict[fields[i]] != nil ? dict[fields[i]] : ""), forKey: fields[i] ); + } + data.add(row) + } + + return CSVExport.export.exportCSV(filename, fields: fields as NSArray, values: data); +} + + ///a free function to make export the CSV file from file name, fields and values public func exportCSV(_ filename:String, fields: [String], values: String) -> String{ diff --git a/SwiftCSVExport.podspec b/SwiftCSVExport.podspec index ec534d9..a732c87 100644 --- a/SwiftCSVExport.podspec +++ b/SwiftCSVExport.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |s| # s.name = "SwiftCSVExport" - s.version = "1.0.1" + s.version = "1.0.2" s.summary = "Simple way to export csv file with rich feature framework in Swift." # This description is used to generate tags and improve search results. diff --git a/SwiftCSVExport.xcodeproj/project.pbxproj b/SwiftCSVExport.xcodeproj/project.pbxproj index 12d854b..eb65bd9 100644 --- a/SwiftCSVExport.xcodeproj/project.pbxproj +++ b/SwiftCSVExport.xcodeproj/project.pbxproj @@ -7,16 +7,13 @@ objects = { /* Begin PBXBuildFile section */ - 0B2F39981E645A4B0019240C /* CSVExport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B2F39971E645A4B0019240C /* CSVExport.swift */; }; 0B54EBD91E4987A00043976B /* SwiftCSVExport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0B54EBCF1E4987A00043976B /* SwiftCSVExport.framework */; }; 0B54EBDE1E4987A00043976B /* SwiftCSVExportTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B54EBDD1E4987A00043976B /* SwiftCSVExportTests.swift */; }; 0B54EBE01E4987A00043976B /* SwiftCSVExport.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B54EBD21E4987A00043976B /* SwiftCSVExport.h */; settings = {ATTRIBUTES = (Public, ); }; }; 0B54EBF91E499C1B0043976B /* SwiftCSVExportOSX.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0B54EBF01E499C1B0043976B /* SwiftCSVExportOSX.framework */; }; 0B54EBFE1E499C1B0043976B /* SwiftCSVExportOSXTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B54EBFD1E499C1B0043976B /* SwiftCSVExportOSXTests.swift */; }; 0B54EC001E499C1B0043976B /* SwiftCSVExportOSX.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B54EBF21E499C1B0043976B /* SwiftCSVExportOSX.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 0B65EF4E1E696AFB00ED048A /* CSVExport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B2F39971E645A4B0019240C /* CSVExport.swift */; }; - 0B65EF4F1E696AFC00ED048A /* CSVExport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B2F39971E645A4B0019240C /* CSVExport.swift */; }; - 0B65EF501E696AFE00ED048A /* CSVExport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B2F39971E645A4B0019240C /* CSVExport.swift */; }; + 0B6178681ECF1B1100BCE646 /* CSVExport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B6178671ECF1B1100BCE646 /* CSVExport.swift */; }; 0B69156F1E4DB535007C9394 /* SwiftCSVExport.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B54EBD21E4987A00043976B /* SwiftCSVExport.h */; }; /* End PBXBuildFile section */ @@ -38,7 +35,6 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 0B2F39971E645A4B0019240C /* CSVExport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CSVExport.swift; path = Sources/CSVExport.swift; sourceTree = SOURCE_ROOT; }; 0B54EBCF1E4987A00043976B /* SwiftCSVExport.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCSVExport.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 0B54EBD21E4987A00043976B /* SwiftCSVExport.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwiftCSVExport.h; sourceTree = ""; }; 0B54EBD31E4987A00043976B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -51,6 +47,7 @@ 0B54EBF81E499C1B0043976B /* SwiftCSVExportOSXTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftCSVExportOSXTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 0B54EBFD1E499C1B0043976B /* SwiftCSVExportOSXTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftCSVExportOSXTests.swift; sourceTree = ""; }; 0B54EBFF1E499C1B0043976B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 0B6178671ECF1B1100BCE646 /* CSVExport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CSVExport.swift; path = Sources/CSVExport.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -90,7 +87,7 @@ 0B2F39961E645A410019240C /* Sources */ = { isa = PBXGroup; children = ( - 0B2F39971E645A4B0019240C /* CSVExport.swift */, + 0B6178671ECF1B1100BCE646 /* CSVExport.swift */, ); name = Sources; sourceTree = ""; @@ -256,12 +253,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0810; - LastUpgradeCheck = 0810; + LastUpgradeCheck = 0830; ORGANIZATIONNAME = vigneshuvi; TargetAttributes = { 0B54EBCE1E4987A00043976B = { CreatedOnToolsVersion = 8.1; - LastSwiftMigration = 0810; + LastSwiftMigration = 0830; ProvisioningStyle = Manual; }; 0B54EBD71E4987A00043976B = { @@ -337,7 +334,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 0B2F39981E645A4B0019240C /* CSVExport.swift in Sources */, + 0B6178681ECF1B1100BCE646 /* CSVExport.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -345,7 +342,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 0B65EF4F1E696AFC00ED048A /* CSVExport.swift in Sources */, 0B54EBDE1E4987A00043976B /* SwiftCSVExportTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -354,7 +350,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 0B65EF4E1E696AFB00ED048A /* CSVExport.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -362,7 +357,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 0B65EF501E696AFE00ED048A /* CSVExport.swift in Sources */, 0B54EBFE1E499C1B0043976B /* SwiftCSVExportOSXTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -401,6 +395,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -455,6 +450,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -614,7 +610,6 @@ 0B54EC051E499C1B0043976B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_IDENTITY = "-"; COMBINE_HIDPI_IMAGES = YES; DEVELOPMENT_TEAM = 7FUQA46NH7; @@ -632,7 +627,6 @@ 0B54EC061E499C1B0043976B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_IDENTITY = "-"; COMBINE_HIDPI_IMAGES = YES; DEVELOPMENT_TEAM = 7FUQA46NH7; diff --git a/SwiftCSVExport.xcodeproj/xcshareddata/xcschemes/SwiftCSVExport.xcscheme b/SwiftCSVExport.xcodeproj/xcshareddata/xcschemes/SwiftCSVExport.xcscheme index 1fd38dd..c126b20 100644 --- a/SwiftCSVExport.xcodeproj/xcshareddata/xcschemes/SwiftCSVExport.xcscheme +++ b/SwiftCSVExport.xcodeproj/xcshareddata/xcschemes/SwiftCSVExport.xcscheme @@ -1,6 +1,6 @@ String{ + let path = "\(directory)/\(csvFileName())" + let fileManager = FileManager.default + if !fileManager.fileExists(atPath: path) { + return ""; + } + return path; + } + + open func exportCSV(_ filename:String, fields: NSArray, values: NSArray) -> String{ + + if filename.length > 0 { + CSVExport.export.fileName = filename; + } + CSVExport.export.cleanup(); + if fields.count > 0 && values.count > 0 { + let result:String = fields.componentsJoined(by: ","); + CSVExport.export.write( text: result) + for dict in values { + let values = (dict as! NSDictionary).allValues as NSArray; + let result:String = values.componentsJoined(by: ","); + CSVExport.export.write( text: result) + } + return CSVExport.export.getFilePath(); + } + return ""; + } + + + ///write content to the current csv file. + open func write(text: String) { + let path = "\(directory)/\(csvFileName())" + let fileManager = FileManager.default + if !fileManager.fileExists(atPath: path) { + do { + try "".write(toFile: path, atomically: true, encoding: encodingType) + } catch _ { + } + } + if let fileHandle = FileHandle(forWritingAtPath: path) { + let writeText = "\(text)\n" + fileHandle.seekToEndOfFile() + fileHandle.write(writeText.data(using: encodingType)!) + fileHandle.closeFile() + print(writeText, terminator: "") + + } + } + + func generateDict(_ fieldsArray: NSArray, valuesArray: NSArray ) -> NSMutableDictionary { + let rowsDictionary:NSMutableDictionary = NSMutableDictionary() + for i in 0.. NSArray { + if string.characters.count > 0 { + return string.components(separatedBy: separatedBy) as NSArray; + } + return []; + } + + open func read(filename: String) -> NSMutableDictionary { + let path = "\(directory)/\(filename)" + return self.readFromPath(filePath:path); + } + + open func read(filepath: String) -> NSMutableDictionary { + return self.readFromPath(filePath:filepath); + } + + /// read content to the current csv file. + open func readFromPath(filePath: String) -> NSMutableDictionary{ + let fileManager = FileManager.default + let output:NSMutableDictionary = NSMutableDictionary() + + // Find the CSV file path is available + if fileManager.fileExists(atPath: filePath) { + do { + // Generate the Local file path URL + let localPathURL: URL = NSURL.fileURL(withPath: filePath); + + // Read the content from Local Path + let csvText = try String(contentsOf: localPathURL, encoding: encodingType); + + // Check the csv count + if csvText.characters.count > 0 { + + // Split based on Newline delimiter + let csvArray = self.splitUsingDelimiter(csvText, separatedBy: "\n") as NSArray + if csvArray.count >= 2 { + var fieldsArray:NSArray = []; + let rowsArray:NSMutableArray = NSMutableArray() + for row in csvArray { + // Get the CSV headers + if((row as! String).contains(csvArray[0] as! String)) { + fieldsArray = self.splitUsingDelimiter(row as! String, separatedBy: ",") as NSArray; + } else { + // Get the CSV values + let valuesArray = self.splitUsingDelimiter(row as! String, separatedBy: ",") as NSArray; + if valuesArray.count == fieldsArray.count && valuesArray.count > 0{ + let rowJson:NSMutableDictionary = self.generateDict(fieldsArray, valuesArray: valuesArray) + if rowJson.allKeys.count > 0 && valuesArray.count == rowJson.allKeys.count && rowJson.allKeys.count == fieldsArray.count { + rowsArray.add(rowJson) + } + } + } + } + + // Set the CSV headers & Values and name in the dict. + if fieldsArray.count > 0 && rowsArray.count > 0 { + output.setObject(fieldsArray, forKey: "fields" as NSCopying) + output.setObject(rowsArray, forKey: "rows" as NSCopying) + output.setObject(localPathURL.lastPathComponent, forKey: "name" as NSCopying) + } + } + } + } + catch { + /* error handling here */ + print("Error while read csv: \(error)", terminator: "") + } + } + return output; + } + + ///do the checks and cleanup + open func cleanup() { + let path = "\(directory)/\(csvFileName())" + let size = fileSize(path) + if size > 0 { + //delete the oldest file + let deletePath = "\(directory)/\(csvFileName())" + let fileManager = FileManager.default + do { + try fileManager.removeItem(atPath: deletePath) + } catch _ { + } + } + } + + ///check the size of a file + func fileSize(_ path: String) -> UInt64 { + let fileManager = FileManager.default + if fileManager.fileExists(atPath: path) { + let attrs: NSDictionary? = try! fileManager.attributesOfItem(atPath: path) as NSDictionary? + if let dict = attrs { + return dict.fileSize() + } + } + return 0 + } + + + ///gets the CSV name + func csvFileName() -> String { + return "\(fileName).csv" + } + + ///get the default CSV directory + class func defaultDirectory() -> String { + var path = "" + let fileManager = FileManager.default + #if os(iOS) + let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) + path = "\(paths[0])/Exports" + #elseif os(OSX) + let urls = fileManager.urls(for: .libraryDirectory, in: .userDomainMask) + if let url = urls.last?.path { + path = "\(url)/Exports" + } + #endif + if !fileManager.fileExists(atPath: path) && path != "" { + do { + try fileManager.createDirectory(atPath: path, withIntermediateDirectories: false, attributes: nil) + } catch _ { + } + } + return path + } + +} + +//MARK: - Export public Methods + +///a free function to make export the CSV file from file name, fields and values +public func exportCSV(_ filename:String, fields: NSArray, values: NSArray) -> String{ + return CSVExport.export.exportCSV(filename, fields: fields, values: values); +} + +///a free function to make export the CSV file from file name, fields and values +public func exportCSV(_ filename:String, fields: [String], values: NSArray) -> String{ + return CSVExport.export.exportCSV(filename, fields: fields as NSArray, values: values); +} + +///a free function to make export the CSV file from file name, fields and values +public func exportCSV(_ filename:String, fields: [String], values: [[String:Any]]) -> String{ + // Convert [String:Any] to NSDictionary + let data:NSMutableArray = NSMutableArray() + for dict in values { + let row:NSMutableDictionary = NSMutableDictionary() + for i in 0 ..< fields.count { + row.setValue((dict[fields[i]] != nil ? dict[fields[i]] : ""), forKey: fields[i] ); + } + data.add(row) + } + + return CSVExport.export.exportCSV(filename, fields: fields as NSArray, values: data); +} + + +///a free function to make export the CSV file from file name, fields and values +public func exportCSV(_ filename:String, fields: [String], values: String) -> String{ + + // Convert String into NSArray of objects. + if let data = (values as NSString).data(using: CSVExport.export.encodingType.rawValue) + { + do { + let parsedObject = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableLeaves) as! NSArray + if parsedObject.count > 0 + { + return CSVExport.export.exportCSV(filename, fields: fields as NSArray, values: parsedObject); + } + } catch { + print("error handling...\(error)") + return ""; + } + } + return ""; +} + +///a free function to make read the CSV file +public func readCSV(_ filePath:String) -> NSMutableDictionary{ + return CSVExport.export.read(filepath: filePath); +} + +///a free function to make read the CSV file +public func readCSVFromDefaultPath(_ fileName:String) -> NSMutableDictionary{ + return CSVExport.export.read(filename: fileName); +} + + diff --git a/SwiftCSVExportTests/SwiftCSVExportTests.swift b/SwiftCSVExportTests/SwiftCSVExportTests.swift index 46957fc..57fcc22 100644 --- a/SwiftCSVExportTests/SwiftCSVExportTests.swift +++ b/SwiftCSVExportTests/SwiftCSVExportTests.swift @@ -26,13 +26,17 @@ class SwiftCSVExportTests: XCTestCase { // This is an example of a functional test case. // Use XCTAssert and related functions to verify your tests produce the correct results. // Able to convert JSON string into CSV. - let string = "[{\"name\":\"vignesh\",\"email\":\"vigneshuvi@gmail.com\"},{\"name\":\"vinoth\",\"email\":\"vinoth@gmail.com\"}]"; - let filePath:String = exportCSV("userlist", fields:["name","email"], values:string); - print(filePath) + let numberArray = [["a": 1, "b": 2, "c": 3], + ["a": 4, "b": 5, "c": 6], + ["a": 7, "b": 8, "c": 9]] + let fields = ["a", "b","c"]; - let fileDetails = readCSV(filePath); - if fileDetails.allKeys.count > 0 { - print(fileDetails) + let path:String = SwiftCSVExport.exportCSV("numberList",fields: fields,values: numberArray); + print(path) + + let numberDetails = readCSV(path); + if numberDetails.allKeys.count > 0 { + print(numberDetails) } }