Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide APIs to read file into more data types #2923

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,8 @@ let package = Package(
.target(
name: "_NIOFileSystemFoundationCompat",
dependencies: [
"_NIOFileSystem"
"_NIOFileSystem",
"NIOFoundationCompat",
],
path: "Sources/NIOFileSystemFoundationCompat"
),
Expand Down
54 changes: 54 additions & 0 deletions Sources/NIOFileSystem/Array+FileSystem.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftNIO open source project
//
// Copyright (c) 2024 Apple Inc. and the SwiftNIO project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) || os(Linux) || os(Android)
import NIOCore

@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
extension Array where Element == UInt8 {
/// Reads the contents of the file at the path.
///
/// - Parameters:
/// - path: The path of the file to read.
/// - maximumSizeAllowed: The maximum size of file which can be read, in bytes, as a ``ByteCount``.
/// - fileSystem: The ``FileSystemProtocol`` instance to use to read the file.
public init(
contentsOf path: FilePath,
maximumSizeAllowed: ByteCount,
fileSystem: some FileSystemProtocol
) async throws {
let byteBuffer = try await fileSystem.withFileHandle(forReadingAt: path) { handle in
try await handle.readToEnd(maximumSizeAllowed: maximumSizeAllowed)
}

self = Self(buffer: byteBuffer)
}

/// Reads the contents of the file at the path using ``FileSystem``.
///
/// - Parameters:
/// - path: The path of the file to read.
/// - maximumSizeAllowed: The maximum size of file which can be read, as a ``ByteCount``.
public init(
contentsOf path: FilePath,
maximumSizeAllowed: ByteCount
) async throws {
self = try await Self(
contentsOf: path,
maximumSizeAllowed: maximumSizeAllowed,
fileSystem: .shared
)
}
}
#endif
56 changes: 56 additions & 0 deletions Sources/NIOFileSystem/ArraySlice+FileSystem.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftNIO open source project
//
// Copyright (c) 2024 Apple Inc. and the SwiftNIO project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) || os(Linux) || os(Android)
import NIOCore

@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
extension ArraySlice where Element == UInt8 {
/// Reads the contents of the file at the path.
///
/// - Parameters:
/// - path: The path of the file to read.
/// - maximumSizeAllowed: The maximum size of file which can be read, in bytes, as a ``ByteCount``.
/// - fileSystem: The ``FileSystemProtocol`` instance to use to read the file.
public init(
contentsOf path: FilePath,
maximumSizeAllowed: ByteCount,
fileSystem: some FileSystemProtocol
) async throws {
let bytes = try await Array(
contentsOf: path,
maximumSizeAllowed: maximumSizeAllowed,
fileSystem: fileSystem
)

self = Self(bytes)
}

/// Reads the contents of the file at the path using ``FileSystem``.
///
/// - Parameters:
/// - path: The path of the file to read.
/// - maximumSizeAllowed: The maximum size of file which can be read, as a ``ByteCount``.
public init(
contentsOf path: FilePath,
maximumSizeAllowed: ByteCount
) async throws {
self = try await Self(
contentsOf: path,
maximumSizeAllowed: maximumSizeAllowed,
fileSystem: .shared
)
}
}
#endif
57 changes: 57 additions & 0 deletions Sources/NIOFileSystemFoundationCompat/Data+FileSystem.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftNIO open source project
//
// Copyright (c) 2024 Apple Inc. and the SwiftNIO project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) || os(Linux) || os(Android)
import _NIOFileSystem
import NIOCore
import NIOFoundationCompat
import struct Foundation.Data

@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
extension Data {
/// Reads the contents of the file at the path.
///
/// - Parameters:
/// - path: The path of the file to read.
/// - maximumSizeAllowed: The maximum size of file which can be read, in bytes, as a ``ByteCount``.
/// - fileSystem: The ``FileSystemProtocol`` instance to use to read the file.
public init(
contentsOf path: FilePath,
maximumSizeAllowed: ByteCount,
fileSystem: some FileSystemProtocol
) async throws {
let byteBuffer = try await fileSystem.withFileHandle(forReadingAt: path) { handle in
try await handle.readToEnd(maximumSizeAllowed: maximumSizeAllowed)
}

self = Data(buffer: byteBuffer)
}

/// Reads the contents of the file at the path using ``FileSystem``.
///
/// - Parameters:
/// - path: The path of the file to read.
/// - maximumSizeAllowed: The maximum size of file which can be read, as a ``ByteCount``.
public init(
contentsOf path: FilePath,
maximumSizeAllowed: ByteCount
) async throws {
self = try await Self(
contentsOf: path,
maximumSizeAllowed: maximumSizeAllowed,
fileSystem: .shared
)
}
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,37 @@ import _NIOFileSystem
import _NIOFileSystemFoundationCompat
import XCTest

@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
extension FileSystem {
func temporaryFilePath(
_ function: String = #function,
inTemporaryDirectory: Bool = true
) async throws -> FilePath {
if inTemporaryDirectory {
let directory = try await self.temporaryDirectory
return self.temporaryFilePath(function, inDirectory: directory)
} else {
return self.temporaryFilePath(function, inDirectory: nil)
}
}

func temporaryFilePath(
_ function: String = #function,
inDirectory directory: FilePath?
) -> FilePath {
let index = function.firstIndex(of: "(")!
let functionName = function.prefix(upTo: index)
let random = UInt32.random(in: .min ... .max)
let fileName = "\(functionName)-\(random)"

if let directory = directory {
return directory.appending(fileName)
} else {
return FilePath(fileName)
}
}
}

@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
final class FileSystemBytesConformanceTests: XCTestCase {
func testTimepecToDate() async throws {
Expand All @@ -33,5 +64,18 @@ final class FileSystemBytesConformanceTests: XCTestCase {
Date(timeIntervalSince1970: 1.000000001)
)
}

func testReadFileIntoData() async throws {
let fs = FileSystem.shared
let path = try await fs.temporaryFilePath()

try await fs.withFileHandle(forReadingAndWritingAt: path) { fileHandle in
_ = try await fileHandle.write(contentsOf: [0, 1, 2], toAbsoluteOffset: 0)
}

let contents = try await Data(contentsOf: path, maximumSizeAllowed: .bytes(1024))

XCTAssertEqual(contents, Data([0, 1, 2]))
}
}
#endif
24 changes: 24 additions & 0 deletions Tests/NIOFileSystemIntegrationTests/FileSystemTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1828,6 +1828,30 @@ extension FileSystemTests {
)
}
}

func testReadIntoArray() async throws {
let path = try await self.fs.temporaryFilePath()

try await self.fs.withFileHandle(forReadingAndWritingAt: path) { fileHandle in
_ = try await fileHandle.write(contentsOf: [0, 1, 2], toAbsoluteOffset: 0)
}

let contents = try await Array(contentsOf: path, maximumSizeAllowed: .bytes(1024))

XCTAssertEqual(contents, [0, 1, 2])
}

func testReadIntoArraySlice() async throws {
let path = try await self.fs.temporaryFilePath()

try await self.fs.withFileHandle(forReadingAndWritingAt: path) { fileHandle in
_ = try await fileHandle.write(contentsOf: [0, 1, 2], toAbsoluteOffset: 0)
}

let contents = try await ArraySlice(contentsOf: path, maximumSizeAllowed: .bytes(1024))

XCTAssertEqual(contents, [0, 1, 2])
}
}

#if !canImport(Darwin) && swift(<5.9.2)
Expand Down
Loading