Skip to content

Commit 24ab841

Browse files
committed
init
0 parents  commit 24ab841

File tree

12 files changed

+393
-0
lines changed

12 files changed

+393
-0
lines changed

.gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.DS_Store
2+
/.build
3+
/Packages
4+
/*.xcodeproj
5+
xcuserdata/

.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// swift-tools-version:5.2
2+
// The swift-tools-version declares the minimum version of Swift required to build this package.
3+
4+
import PackageDescription
5+
6+
let package = Package(
7+
name: "FileUtils",
8+
products: [
9+
.library(
10+
name: "FileUtils",
11+
targets: ["FileUtils"]),
12+
],
13+
dependencies: [
14+
// .package(url: /* package url */, from: "1.0.0"),
15+
],
16+
targets: [
17+
.target(
18+
name: "FileUtils",
19+
dependencies: []),
20+
.testTarget(
21+
name: "FileUtilsTests",
22+
dependencies: ["FileUtils"]),
23+
]
24+
)

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# FileUtils
2+
3+
A description of this package.

Sources/FileUtils/FileReader.swift

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//
2+
// FileReader.swift
3+
//
4+
//
5+
// Created by Oleh Hudeichuk on 26.06.2020.
6+
//
7+
8+
import Foundation
9+
10+
class FileReader {
11+
12+
let fileURL: URL
13+
private var file: UnsafeMutablePointer<FILE>? = nil
14+
15+
init(fileURL: URL) {
16+
self.fileURL = fileURL
17+
}
18+
19+
init(filePath: String) {
20+
guard let fileURL: URL = URL(string: filePath) else { fatalError("Can't convert path \(filePath) to URL") }
21+
self.fileURL = fileURL
22+
}
23+
24+
deinit {
25+
if self.file != nil { fatalError("Please, close file descriptor.") }
26+
}
27+
28+
func open() throws {
29+
guard let descriptor = fopen(fileURL.path, "r") else {
30+
throw NSError(domain: NSPOSIXErrorDomain, code: Int(errno), userInfo: nil)
31+
}
32+
self.file = descriptor
33+
}
34+
35+
func close() {
36+
if let descriptor = self.file {
37+
self.file = nil
38+
let success: Bool = fclose(descriptor) == 0
39+
assert(success)
40+
}
41+
}
42+
43+
func readLine(maxLength: Int = 4096) throws -> String? {
44+
guard let descriptor = self.file else {
45+
throw NSError(domain: NSPOSIXErrorDomain, code: Int(EBADF), userInfo: nil)
46+
}
47+
var buffer = [CChar](repeating: 0, count: maxLength)
48+
guard fgets(&buffer, Int32(maxLength), descriptor) != nil else {
49+
if feof(descriptor) != 0 {
50+
return nil
51+
} else {
52+
throw NSError(domain: NSPOSIXErrorDomain, code: Int(errno), userInfo: nil)
53+
}
54+
}
55+
56+
return String(cString: buffer)
57+
}
58+
}

Sources/FileUtils/FileUtils.swift

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import Foundation
2+
3+
4+
public class FileUtils {}
5+
6+
public extension FileUtils {
7+
8+
class func clearFile(_ url: URL?) {
9+
clearFile(url?.path)
10+
}
11+
12+
class func clearFile(_ path: String?) {
13+
guard let path = path else { return }
14+
do {
15+
try "".write(to: URL(fileURLWithPath: path), atomically: true, encoding: .utf8)
16+
} catch {
17+
fatalError("CLEAR FILE: Can't write to file \(path)")
18+
}
19+
}
20+
21+
class func createFile(_ url: URL?) {
22+
createFile(url?.path)
23+
}
24+
25+
class func createFile(_ path: String?) {
26+
guard let path = path else { return }
27+
FileManager.default.createFile(atPath: path, contents: nil, attributes: nil)
28+
}
29+
30+
class func urls(for directory: FileManager.SearchPathDirectory, skipsHiddenFiles: Bool = true ) -> [URL] {
31+
var fileURLs: [URL] = .init()
32+
33+
if let documentsURL = FileManager.default.urls(for: directory, in: .userDomainMask).first {
34+
do {
35+
fileURLs = try FileManager.default.contentsOfDirectory(at: documentsURL,
36+
includingPropertiesForKeys: nil,
37+
options: skipsHiddenFiles ? [.skipsHiddenFiles] : [] )
38+
} catch {}
39+
}
40+
41+
return fileURLs
42+
}
43+
44+
class func urls(for directory: String, skipsHiddenFiles: Bool = true ) -> [URL] {
45+
guard let documentsURL = URL(string: directory) else { return [] }
46+
return urls(for: documentsURL, skipsHiddenFiles: skipsHiddenFiles)
47+
}
48+
49+
class func urls(for directory: URL, skipsHiddenFiles: Bool = true ) -> [URL] {
50+
do {
51+
return try FileManager.default.contentsOfDirectory(at: directory,
52+
includingPropertiesForKeys: [],
53+
options: skipsHiddenFiles ? [.skipsHiddenFiles] : [] )
54+
} catch {
55+
return []
56+
}
57+
}
58+
59+
class func readDirectory(for directory: URL, skipsHiddenFiles: Bool = true ) -> [URL] {
60+
urls(for: directory, skipsHiddenFiles: skipsHiddenFiles)
61+
}
62+
63+
class func readDirectory(for directory: String, skipsHiddenFiles: Bool = true ) -> [URL] {
64+
urls(for: directory, skipsHiddenFiles: skipsHiddenFiles)
65+
}
66+
67+
class func isDirectory(_ url: URL) -> Bool {
68+
(try? url.resourceValues(forKeys: [.isDirectoryKey]))?.isDirectory ?? false
69+
}
70+
71+
class func isDirectory(_ path: String) -> Bool {
72+
guard let url = URL(string: path) else { fatalError("\(path) - can not convert to URL") }
73+
return isDirectory(url)
74+
}
75+
76+
class func isFile(_ url: URL) -> Bool {
77+
!isDirectory(url)
78+
}
79+
80+
class func isFile(_ path: String) -> Bool {
81+
guard let url = URL(string: path) else { fatalError("\(path) - can not convert to URL") }
82+
return isFile(url)
83+
}
84+
85+
class func fileExist(_ url: URL) -> Bool {
86+
fileExist(url.path)
87+
}
88+
89+
class func fileExist(_ path: String) -> Bool {
90+
FileManager.default.fileExists(atPath: path)
91+
}
92+
93+
class func directoryExist(_ url: URL) -> Bool {
94+
directoryExist(url.path)
95+
}
96+
97+
class func directoryExist(_ path: String) -> Bool {
98+
var isDirectory = ObjCBool(true)
99+
let exists = FileManager.default.fileExists(atPath: path, isDirectory: &isDirectory)
100+
return exists && isDirectory.boolValue
101+
}
102+
}

Sources/FileUtils/Mode.swift

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//
2+
// Mode.swift
3+
//
4+
//
5+
// Created by Oleh Hudeichuk on 26.06.2020.
6+
//
7+
8+
import Foundation
9+
10+
public extension FileUtils {
11+
12+
struct Mode: OptionSet {
13+
14+
public var rawValue: Int
15+
public typealias RawValue = Int
16+
public init(rawValue: RawValue) {
17+
self.rawValue = rawValue
18+
}
19+
20+
// public static var rewrite = Mode(rawValue: 1)
21+
public static var append = Mode(rawValue: 2)
22+
public static var clear = Mode(rawValue: 3)
23+
public static var createFile = Mode(rawValue: 4)
24+
}
25+
}

Sources/FileUtils/ReadFile.swift

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//
2+
// ReadFile.swift
3+
//
4+
//
5+
// Created by Oleh Hudeichuk on 27.06.2020.
6+
//
7+
8+
import Foundation
9+
10+
public extension FileUtils {
11+
12+
class func readFile(_ url: URL, encoding: String.Encoding = .utf8) throws -> String {
13+
try String(contentsOf: url, encoding: encoding)
14+
}
15+
16+
class func readFileByLine(_ url: URL, _ handler: (_ line: String) -> Void) throws {
17+
let file: FileReader = .init(fileURL: url)
18+
try file.open()
19+
defer { file.close() }
20+
while let line: String = try file.readLine() {
21+
handler(line)
22+
}
23+
}
24+
25+
class func readFileByLine(_ path: String, _ handler: (_ line: String) -> Void) throws {
26+
let file: FileReader = .init(filePath: path)
27+
try file.open()
28+
defer { file.close() }
29+
while let line: String = try file.readLine() {
30+
handler(line)
31+
}
32+
}
33+
}

Sources/FileUtils/WriteFile.swift

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
//
2+
// WriteFile.swift
3+
//
4+
//
5+
// Created by Oleh Hudeichuk on 27.06.2020.
6+
//
7+
8+
import Foundation
9+
10+
public extension FileUtils {
11+
12+
class func writeFile(to: URL?,
13+
_ data: Data?,
14+
_ mode: FileUtils.Mode = [.clear]
15+
) throws {
16+
if data == nil || to == nil { return }
17+
if mode.contains(.createFile) && !fileExist(to!) {
18+
createFile(to)
19+
}
20+
if mode.contains(.clear) { clearFile(to) }
21+
let fileHandle: FileHandle = try FileHandle(forWritingTo: to!)
22+
if mode.contains(.append) {
23+
fileHandle.seekToEndOfFile()
24+
}
25+
fileHandle.write(data!)
26+
fileHandle.closeFile()
27+
}
28+
29+
class func writeFile(to path: String?,
30+
_ data: Data?,
31+
_ mode: FileUtils.Mode = [.clear]
32+
) {
33+
if data == nil || path == nil { return }
34+
if mode.contains(.createFile) && !fileExist(path!) {
35+
createFile(path)
36+
}
37+
if mode.contains(.clear) { clearFile(path) }
38+
let fileHandle: FileHandle? = FileHandle(forWritingAtPath: path!)
39+
if mode.contains(.append) {
40+
fileHandle?.seekToEndOfFile()
41+
}
42+
fileHandle?.write(data!)
43+
fileHandle?.closeFile()
44+
}
45+
46+
class func writeFile(to path: String?,
47+
_ text: String?,
48+
_ encoding: String.Encoding = .utf8,
49+
_ mode: FileUtils.Mode = [.clear]
50+
) {
51+
writeFile(to: path, text?.data(using: encoding))
52+
}
53+
54+
class func writeFile(to: URL?,
55+
_ text: String?,
56+
_ encoding: String.Encoding = .utf8,
57+
_ mode: FileUtils.Mode = [.clear]
58+
) throws {
59+
try writeFile(to: to, text?.data(using: encoding))
60+
}
61+
62+
class func writeFilePosix(to: String,
63+
_ text: String,
64+
_ encoding: String.Encoding = .utf8,
65+
_ oflag: Int32 = O_TRUNC | O_WRONLY | O_CREAT,
66+
_ mode: mode_t = 0o755
67+
) {
68+
let fileDescriptor: Int32 = open(to, oflag, mode)
69+
if fileDescriptor < 0 {
70+
perror("could not open \(to)")
71+
} else {
72+
guard let size: Int = text.data(using: encoding)?.count else { return }
73+
write(fileDescriptor, text, size)
74+
close(fileDescriptor)
75+
}
76+
}
77+
78+
class func writeFilePosix(to: String,
79+
_ data: Data?,
80+
_ oflag: Int32 = O_TRUNC | O_WRONLY | O_CREAT,
81+
_ mode: mode_t = 0o755
82+
) {
83+
let fileDescriptor: Int32 = open(to, oflag, mode)
84+
if fileDescriptor < 0 {
85+
perror("could not open \(to)")
86+
} else {
87+
guard let size: Int = data?.count else { return }
88+
var data = data
89+
withUnsafePointer(to: &data!) { (pointer: UnsafePointer<Data>) -> Void in
90+
write(fileDescriptor, pointer, size)
91+
}
92+
close(fileDescriptor)
93+
}
94+
}
95+
}
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import XCTest
2+
@testable import FileUtils
3+
4+
final class FileUtilsTests: XCTestCase {
5+
func testExample() {
6+
// This is an example of a functional test case.
7+
// Use XCTAssert and related functions to verify your tests produce the correct
8+
// results.
9+
// XCTAssertEqual(FileUtils().text, "Hello, World!")
10+
}
11+
12+
static var allTests = [
13+
("testExample", testExample),
14+
]
15+
}
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#if !canImport(ObjectiveC)
2+
import XCTest
3+
4+
extension FileUtilsTests {
5+
// DO NOT MODIFY: This is autogenerated, use:
6+
// `swift test --generate-linuxmain`
7+
// to regenerate.
8+
static let __allTests__FileUtilsTests = [
9+
("testExample", testExample),
10+
]
11+
}
12+
13+
public func __allTests() -> [XCTestCaseEntry] {
14+
return [
15+
testCase(FileUtilsTests.__allTests__FileUtilsTests),
16+
]
17+
}
18+
#endif

0 commit comments

Comments
 (0)