Print the size (megabytes) of Data in Swift - ios

I have a variable fileData of Data type and I am struggling to find how to print the size of this.
In the past NSData you would print the length but unable to do that with this type.
How to print the size of a Data in Swift?

Use yourData.count and divide by 1024 * 1024. Using Alexanders excellent suggestion:
func stackOverflowAnswer() {
if let data = #imageLiteral(resourceName: "VanGogh.jpg").pngData() {
print("There were \(data.count) bytes")
let bcf = ByteCountFormatter()
bcf.allowedUnits = [.useMB] // optional: restricts the units to MB only
bcf.countStyle = .file
let string = bcf.string(fromByteCount: Int64(data.count))
print("formatted result: \(string)")
}
}
With the following results:
There were 28865563 bytes
formatted result: 28.9 MB

If your goal is to print the size to the use, use ByteCountFormatter
import Foundation
let byteCount = 512_000 // replace with data.count
let bcf = ByteCountFormatter()
bcf.allowedUnits = [.useMB] // optional: restricts the units to MB only
bcf.countStyle = .file
let string = bcf.string(fromByteCount: Int64(byteCount))
print(string)

You can use count of Data object and still you can use length for NSData

Swift 5.1
extension Int {
var byteSize: String {
return ByteCountFormatter().string(fromByteCount: Int64(self))
}
}
Usage:
let yourData = Data()
print(yourData.count.byteSize)

Following accepted answer I've created simple extension:
extension Data {
func sizeString(units: ByteCountFormatter.Units = [.useAll], countStyle: ByteCountFormatter.CountStyle = .file) -> String {
let bcf = ByteCountFormatter()
bcf.allowedUnits = units
bcf.countStyle = .file
return bcf.string(fromByteCount: Int64(count))
}}

Enter your file URL in the following code to get file size in MB, I hope this helps you.
let data = NSData(contentsOf: FILE URL)!
let fileSize = Double(data.count / 1048576) //Convert in to MB
print("File size in MB: ", fileSize)

A quick extension for getting Data size in megabytes as Double.
extension Data {
func getSizeInMB() -> Double {
let bcf = ByteCountFormatter()
bcf.allowedUnits = [.useMB]
bcf.countStyle = .file
let string = bcf.string(fromByteCount: Int64(self.count)).replacingOccurrences(of: ",", with: ".")
if let double = Double(string.replacingOccurrences(of: " MB", with: "")) {
return double
}
return 0.0
}
}

If you want to just see number of bytes, printing the data object directly can give that to you.
let dataObject = Data()
print("Size is \(dataObject)")
Should give you:
Size is 0 bytes
In other words, .count won't be necessary in newer Swift 3.2 or higher.

To get the size of a string, adapted from #mozahler's answer
if let data = "some string".data(using: .utf8)! {
print("There were \(data.count) bytes")
let bcf = ByteCountFormatter()
bcf.allowedUnits = [.useKB] // optional: restricts the units to MB only
bcf.countStyle = .file
let string = bcf.string(fromByteCount: Int64(data.count))
print("formatted result: \(string)")
}

func sizeInMB(data: Data) -> String {
let bytes = Double(data.count)
let megabytes = bytes / (1024 * 1024)
return String(format: "%.2f MB", megabytes)
}
The following takes in a Data object as an argument and calculates the size of that Data in megabytes. The size is then returned as a String with a maximum of 2 decimal places.

count should suit your needs. You'll need to convert bytes to megabytes (Double(data.count) / pow(1024, 2))

Related

ByteCountFormatter number formate

I'm using ByteCountFormatter for converting Byte to Appropriate String,
func sizeFormate(size: Int) -> String {
let bcf = ByteCountFormatter()
bcf.allowedUnits = [.useMB,.useGB]
bcf.countStyle = .binary
return bcf.string(fromByteCount: Int64(size))
}
for example:
sizeFormate(size: 763917940) // output: 728.5 MB
// what I need is 728 MB // digit should not have fraction part
How can we achieve this formate?
ByteCountFormatter have one property named: isAdaptive and by Default it is true. To hide fraction part just make this false
Updated code:
func sizeFormate(size: Int) -> String {
let bcf = ByteCountFormatter()
bcf.allowedUnits = [.useMB,.useGB]
bcf.countStyle = .binary
bcf.isAdaptive = false // change
return bcf.string(fromByteCount: Int64(size))
}
Note: keep that in mind that it round of from 0.5 to 1
it still shows fraction digits..
any other way?

How to convert data into little endian format?

var val = 1240;
convert into little endian formate swift 3
Ex: 1500 (0x5DC) to 0xDC050000
let value = UInt16(bigEndian: 1500)
print(String(format:"%04X", value.bigEndian)) //05DC
print(String(format:"%04X", value.littleEndian)) //DC05
Make sure you are actually using the bigEndian initializer.
With 32-bit integers:
let value = UInt32(bigEndian: 1500)
print(String(format:"%08X", value.bigEndian)) //000005DC
print(String(format:"%08X", value.littleEndian)) //DC050000
If you want 1500 as an array of bytes in little-endian order:
var value = UInt32(littleEndian: 1500)
let array = withUnsafeBytes(of: &value) { Array($0) }
If you want that as a Data:
let data = Data(array)
Or, if you really wanted that as a hex string:
let string = array.map { String(format: "%02x", $0) }.joined()
let timeDevide = self.setmiliSecond/100
var newTime = UInt32(littleEndian: timeDevide)
let arrayTime = withUnsafeBytes(of: &newTime)
{Array($0)}
let timeDelayValue = [0x0B] + arrayTime
You can do something like
//: Playground - noun: a place where people can play
import UIKit
extension String {
func hexadecimal() -> Data? {
var data = Data(capacity: count / 2)
let regex = try! NSRegularExpression(pattern: "[0-9a-f]{1,2}", options: .caseInsensitive)
regex.enumerateMatches(in: self, range: NSRange(location: 0, length: utf16.count)) { match, _, _ in
let byteString = (self as NSString).substring(with: match!.range)
var num = UInt8(byteString, radix: 16)!
data.append(&num, count: 1)
}
guard !data.isEmpty else { return nil }
return data
}
}
func convertInputValue<T: FixedWidthInteger>(_ inputValue: Data) -> T where T: CVarArg {
let stride = MemoryLayout<T>.stride
assert(inputValue.count % (stride / 2) == 0, "invalid pack size")
let fwInt = T.init(littleEndian: inputValue.withUnsafeBytes { $0.pointee })
let valuefwInt = String(format: "%0\(stride)x", fwInt).capitalized
print(valuefwInt)
return fwInt
}
var inputString = "479F"
var inputValue: Data! = inputString.hexadecimal()
let val: UInt16 = convertInputValue(inputValue) //9F47
inputString = "479F8253"
inputValue = inputString.hexadecimal()
let val2: UInt32 = convertInputValue(inputValue) //53829F47

Convert Kelvin into Celsius in Swift

I'm trying to retrieve the temperature from the users current location.
I am using the API from OpenWeatherMap. The problem is, they provide the temperature in Kelvin as default, and I would like it in Celsius.
I understand that I just need to subtract 273.15 from the kelvin value....? But i'm struggling to figure out where to do that.
My code for setting my labels:
var jsonData: AnyObject?
func setLabels(weatherData: NSData) {
do {
self.jsonData = try NSJSONSerialization.JSONObjectWithData(weatherData, options: []) as! NSDictionary
} catch {
//handle error here
}
if let name = jsonData!["name"] as? String {
locationLabel.text = "using your current location, \(name)"
}
if let main = jsonData!["main"] as? NSDictionary {
if let temperature = main["temp"] as? Double {
self.tempLabel.text = String(format: "%.0f", temperature)
}
}
}
Can anyone help me get this right please, as I'm really not sure where to start, thanks.
Let me know if you need to see more of my code.
if let kelvinTemp = main["temp"] as? Double {
let celsiusTemp = kelvinTemp - 273.15
self.tempLabel.text = String(format: "%.0f", celsiusTemp)
}
or simply
self.tempLabel.text = String(format: "%.0f", temperature - 273.15)
For Swift 4.2:
Use a Measurement Formatter.
let mf = MeasurementFormatter()
This method converts one temperature type (Kelvin, Celsius, Fahrenheit) to another:
func convertTemp(temp: Double, from inputTempType: UnitTemperature, to outputTempType: UnitTemperature) -> String {
mf.numberFormatter.maximumFractionDigits = 0
mf.unitOptions = .providedUnit
let input = Measurement(value: temp, unit: inputTempType)
let output = input.converted(to: outputTempType)
return mf.string(from: output)
}
Usage:
let temperature = 291.0
let celsius = convertTemp(temp: temperature, from: .kelvin, to: .celsius) // 18°C
let fahrenheit = convertTemp(temp: temperature, from: .kelvin, to: .fahrenheit) // 64°F
To output the localized temperature format, remove the line mf.unitOptions = .providedUnit
From the code above, it seems to me the right place to do this would be right after you get the temperature
if let temperatureInKelvin = main["temp"] as? Double {
let temperatureInCelsius = temperatureInKelvin - 273.15
self.tempLabel.text = String(format: "%.0f", temperature)
}
In the future though, I would probably parse your JSON values in a separate class and store them in a model object which you can call later on.
A simpler example of the above handy function (updated for Swift 5.3) would be something like:
func convertTemperature(temp: Double, from inputTempType: UnitTemperature, to outputTempType: UnitTemperature) -> Double {
let input = Measurement(value: temp, unit: inputTempType)
let output = input.converted(to: outputTempType)
return output.value
}
Here:
self.tempLabel.text = String(format: "%.0f", temperature - 273.15)
or you can do it here (pseudo syntax as I don't know Swift that well):
if let temperature = (main["temp"] as? Double) - 273.15 {
self.tempLabel.text = String(format: "%.0f", temperature)
}

How to get image file size in Swift?

I am using
UIImagePickerControllerDelegate,
UINavigationControllerDelegate,
UIPopoverControllerDelegate
these delegates for choosing image from my gallery or my camera. So, how can I get image file size after choosing an image?
I want to use this:
let filePath = "your path here"
var fileSize : UInt64 = 0
do {
let attr : NSDictionary? = try NSFileManager.defaultManager().attributesOfItemAtPath(filePath)
if let _attr = attr {
fileSize = _attr.fileSize();
print(fileSize)
}
} catch {
}
but here I need a path, but how can I get without a path, just by image file?
Please check the google for 1 kb to bytes it will be 1000.
https://www.google.com/search?q=1+kb+%3D+how+many+bytes&oq=1+kb+%3D+how+many+bytes&aqs=chrome..69i57.8999j0j1&sourceid=chrome&ie=UTF-8
So while getting the proper size I’ve added multiple scenario by adding image in App Bundle and in photos in simulator.
Well the image which I took from my Mac was of 299.0 KB.
Scenario 1: Adding image to Application Bundle
On adding image in your Xcode the size of the image will remain same in project directory. But you get it from its path the size will be reduced to 257.0 KB. Which is the actual size of the image used in the device or simulator.
guard let aStrUrl = Bundle.main.path(forResource: "1", ofType: "png") else { return }
let aUrl = URL(fileURLWithPath: aStrUrl)
print("Img size = \((Double(aUrl.fileSize) / 1000.00).rounded()) KB")
extension URL {
var attributes: [FileAttributeKey : Any]? {
do {
return try FileManager.default.attributesOfItem(atPath: path)
} catch let error as NSError {
print("FileAttribute error: \(error)")
}
return nil
}
var fileSize: UInt64 {
return attributes?[.size] as? UInt64 ?? UInt64(0)
}
var fileSizeString: String {
return ByteCountFormatter.string(fromByteCount: Int64(fileSize), countStyle: .file)
}
var creationDate: Date? {
return attributes?[.creationDate] as? Date
}
}
Scenario 2: Adding image to Photos in Simulator
On adding image to photos in simulator or device the size of the image increased from 299.0 KB to 393.0 KB. Which is the actual size of the image stored in the device or simulator’s document directory.
Swift 4 and earlier
var image = info[UIImagePickerControllerOriginalImage] as! UIImage
var imgData: NSData = NSData(data: UIImageJPEGRepresentation((image), 1))
// var imgData: NSData = UIImagePNGRepresentation(image)
// you can also replace UIImageJPEGRepresentation with UIImagePNGRepresentation.
var imageSize: Int = imgData.count
print("size of image in KB: %f ", Double(imageSize) / 1000.0)
Swift 5
let image = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
let imgData = NSData(data: image.jpegData(compressionQuality: 1)!)
var imageSize: Int = imgData.count
print("actual size of image in KB: %f ", Double(imageSize) / 1000.0)
By adding .rounded() it will give you 393.0 KB and without using it it will give 393.442 KB. So please check the image size manually once using the above code. As the size of image may vary in different devices and mac. I've check it only on mac mini and simulator iPhone XS.
extension UIImage {
public enum DataUnits: String {
case byte, kilobyte, megabyte, gigabyte
}
func getSizeIn(_ type: DataUnits)-> String {
guard let data = self.pngData() else {
return ""
}
var size: Double = 0.0
switch type {
case .byte:
size = Double(data.count)
case .kilobyte:
size = Double(data.count) / 1024
case .megabyte:
size = Double(data.count) / 1024 / 1024
case .gigabyte:
size = Double(data.count) / 1024 / 1024 / 1024
}
return String(format: "%.2f", size)
}
}
Usage example : print("Image size \(yourImage.getSizeIn(.megabyte)) mb")
Swift 3/4:
if let imageData = UIImagePNGRepresentation(image) {
let bytes = imageData.count
let kB = Double(bytes) / 1000.0 // Note the difference
let KB = Double(bytes) / 1024.0 // Note the difference
}
Please note the difference between kB and KB. Answering here because in my case we had an issue while we considered kilobyte as 1024 bytes but server side considered it as 1000 bytes which caused an issue. Link to learn more.
PS. Almost sure you'll go with kB (1000).
Details
Xcode 10.2.1 (10E1001), Swift 5
Solution
extension String {
func getNumbers() -> [NSNumber] {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
let charset = CharacterSet.init(charactersIn: " ,.")
return matches(for: "[+-]?([0-9]+([., ][0-9]*)*|[.][0-9]+)").compactMap { string in
return formatter.number(from: string.trimmingCharacters(in: charset))
}
}
// https://stackoverflow.com/a/54900097/4488252
func matches(for regex: String) -> [String] {
guard let regex = try? NSRegularExpression(pattern: regex, options: [.caseInsensitive]) else { return [] }
let matches = regex.matches(in: self, options: [], range: NSMakeRange(0, self.count))
return matches.compactMap { match in
guard let range = Range(match.range, in: self) else { return nil }
return String(self[range])
}
}
}
extension UIImage {
func getFileSizeInfo(allowedUnits: ByteCountFormatter.Units = .useMB,
countStyle: ByteCountFormatter.CountStyle = .file) -> String? {
// https://developer.apple.com/documentation/foundation/bytecountformatter
let formatter = ByteCountFormatter()
formatter.allowedUnits = allowedUnits
formatter.countStyle = countStyle
return getSizeInfo(formatter: formatter)
}
func getFileSize(allowedUnits: ByteCountFormatter.Units = .useMB,
countStyle: ByteCountFormatter.CountStyle = .memory) -> Double? {
guard let num = getFileSizeInfo(allowedUnits: allowedUnits, countStyle: countStyle)?.getNumbers().first else { return nil }
return Double(truncating: num)
}
func getSizeInfo(formatter: ByteCountFormatter, compressionQuality: CGFloat = 1.0) -> String? {
guard let imageData = jpegData(compressionQuality: compressionQuality) else { return nil }
return formatter.string(fromByteCount: Int64(imageData.count))
}
}
Usage
guard let image = UIImage(named: "img") else { return }
if let imageSizeInfo = image.getFileSizeInfo() {
print("\(imageSizeInfo), \(type(of: imageSizeInfo))") // 51.9 MB, String
}
if let imageSizeInfo = image.getFileSizeInfo(allowedUnits: .useBytes, countStyle: .file) {
print("\(imageSizeInfo), \(type(of: imageSizeInfo))") // 54,411,697 bytes, String
}
if let imageSizeInfo = image.getFileSizeInfo(allowedUnits: .useKB, countStyle: .decimal) {
print("\(imageSizeInfo), \(type(of: imageSizeInfo))") // 54,412 KB, String
}
if let size = image.getFileSize() {
print("\(size), \(type(of: size))") // 51.9, Double
}
Swift 3
let uploadData = UIImagePNGRepresentation(image)
let array = [UInt8](uploadData)
print("Image size in bytes:\(array.count)")
try this for getting size from url
func fileSize(url: URL) -> String? {
var fileSize:Int?
do {
let resources = try url.resourceValues(forKeys:[.fileSizeKey])
fileSize = resources.fileSize!
print ("\(String(describing: fileSize))")
} catch {
print("Error: \(error)")
}
// bytes
if fileSize! < 999 {
return String(format: "%lu bytes", CUnsignedLong(bitPattern: fileSize!))
}
// KB
var floatSize = Float(fileSize! / 1000)
if floatSize < 999 {
return String(format: "%.1f KB", floatSize)
}
// MB
floatSize = floatSize / 1000
if floatSize < 999 {
return String(format: "%.1f MB", floatSize)
}
// GB
floatSize = floatSize / 1000
return String(format: "%.1f GB", floatSize)
}
Use Example
let sizeInString = fileSize(url: url)
print("FileSize = "+sizeInString!)
let selectedImage = info[UIImagePickerControllerOriginalImage] as! UIImage
let selectedImageData: NSData = NSData(data:UIImageJPEGRepresentation((selectedImage), 1))
let selectedImageSize:Int = selectedImageData.length
print("Image Size: %f KB", selectedImageSize /1024.0)
let data = UIImageJPEGRepresentation(image, 1)
let imageSize = data?.count
Duplicate of How to get the size of a UIImage in KB?
let imageData = UIImageJPEGRepresentation(image, 1)
let imageSize = imageData?.count
UIImageJPEGRepresentation — returns the Data object for the specified image in JPEG format. The value 1.0 represents the least compression (close to original image).
imageData?.count — return data length (chars count equals bytes).
Important! UIImageJPEGRepresentation or UIImagePNGRepresentation will not return the original image. But if use given Data as source for uploading - than file size be the same as on the server (even using compression).
Swift 4.2
let jpegData = image.jpegData(compressionQuality: 1.0)
let jpegSize: Int = jpegData?.count ?? 0
print("size of jpeg image in KB: %f ", Double(jpegSize) / 1024.0)
Try this code (Swift 4.2)
extension URL {
var attributes: [FileAttributeKey : Any]? {
do {
return try FileManager.default.attributesOfItem(atPath: path)
} catch let error as NSError {
print("FileAttribute error: \(error)")
}
return nil
}
var fileSize: UInt64 {
return attributes?[.size] as? UInt64 ?? UInt64(0)
}
var fileSizeString: String {
return ByteCountFormatter.string(fromByteCount: Int64(fileSize), countStyle: .file)
}
var creationDate: Date? {
return attributes?[.creationDate] as? Date
}
}
And use example
guard let aStrUrl = Bundle.main.path(forResource: "example_image", ofType: "jpg") else { return }
let aUrl = URL(fileURLWithPath: aStrUrl)
print("Img size = \((Double(aUrl.fileSize) / 1000.00).rounded()) KB")
//Swift 4
if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
///check image Size
let imgData = NSData(data: UIImageJPEGRepresentation((pickedImage), 1)!)
let imageSize: Int = imgData.count
print("size of image in KB: %f ", Double(imageSize) / 1024.0)
print("size of image in MB: %f ", Double(imageSize) / 1024.0 / 1024)
}
I make work around data units conversion :
Bytes -> KB -> MB -> GB -> ... -> Extremest Monster Data
enum dataUnits:CaseIterable {
case B //Byte
case KB //kilobyte
case MB //megabyte
case GB //gigabyte
case TB //terabyte
case PB //petabyte
case EB //exabyte
case ZB //zettabyte
case YB //yottabyte
case BD //Big Data
case BBx // Extra Big Bytes
case BBxx // 2 time Extra Big Bytes
case BBxxx // 3 time Extra Big Bytes
case BBxxxx // 4 time Extra Big Bytes
case MBB // Monster Big Bytes
}
func convertStorageUnit(data n:Double,inputDataUnit unitLevel:Int,roundPoint:Int = 2,nG:Double = 1000.0)->String{
if(n>=nG){
return convertStorageUnit(data:n/1024,inputDataUnit:unitLevel+1)
}else{
let ut = unitLevel > dataUnits.allCases.count + 1 ? "Extreme Monster Data" : dataUnits.allCases.map{"\($0)"}[unitLevel]
return "\(String(format:"%.\(roundPoint)f",n)) \(ut)"
}
}
print(
convertStorageUnit(data:99922323343439789798789898989897987945454545920,
inputDataUnit:dataUnits.allCases.firstIndex(of: .B)!,roundPoint: 0)
)
output : 8.87 PB
Note: Input data length should be less than 64-bit OR Change data type According
Try this
import Darwin
...
let size = malloc_size(&_attr)

Convert UIImage to byte array in swift

How can I convert a UIimage into a Byte Array, so I can upload it into my web service?
You can actually use a couple of lines to do it
guard let image = UIImage(named: "someImage"),
let data = image.jpegData(compressionQuality: 1.0) else { return }
// OR
guard let image = UIImage(named: "someImage"),
let data = image.pngData() else { return }
The number should range from 0.0 to 1.0 and sets the jpeg quality. PNG is lossless so there is no need for compression quality identifier but be aware that the file size can be about 10 times higher
--- update ---
Updated for Swift 5.1
You can convert UIImage to NSData and pass it to this method
func getArrayOfBytesFromImage(imageData:NSData) -> NSMutableArray
{
// the number of elements:
let count = imageData.length / sizeof(UInt8)
// create array of appropriate length:
var bytes = [UInt8](count: count, repeatedValue: 0)
// copy bytes into array
imageData.getBytes(&bytes, length:count * sizeof(UInt8))
var byteArray:NSMutableArray = NSMutableArray()
for (var i = 0; i < count; i++) {
byteArray.addObject(NSNumber(unsignedChar: bytes[i]))
}
return byteArray
}
Swift 5, iOS 14 version based on toofani answer, minimal changes
func getArrayOfBytesFromImage(imageData:NSData) -> Array<UInt8>
{
// the number of elements:
let count = imageData.length / MemoryLayout<Int8>.size
// create array of appropriate length:
var bytes = [UInt8](repeating: 0, count: count)
// copy bytes into array
imageData.getBytes(&bytes, length:count * MemoryLayout<Int8>.size)
var byteArray:Array = Array<UInt8>()
for i in 0 ..< count {
byteArray.append(bytes[i])
}
return byteArray
}
So a complete sequence looks like this... assuming I got a UIImage I extract the data and then recombine it.
let data = imageX.pngData()
bytes = getArrayOfBytesFromImage(imageData: data! as NSData)
let datos: NSData = NSData(bytes: bytes, length: bytes.count)
newImage = UIImage(data: datos as Data) // Note it's optional. Don't force unwrap!!!

Resources