Entrada e saída de dados
A Entrada e saída de dados é a forma como o programa conversa com o mundo externo. Em uma aplicação CLI, isso normalmente significa:
Entrada Ler dados digitados pelo usuário.
Saída Mostrar informações na tela.
Arquivos Ler e salvar dados em arquivos simples
Em Dart, para trabalhar com terminal e arquivos, usamos a biblioteca, como a import 'dart:io';. Ela é parecida com algumas funções do Python, como:
- input()
- print()
- open()
Exibindo informações na tela
O jeito mais simples de mostrar algo no terminal é usando print().
void main() {
print('Sistema iniciado');
print('Carregando usuários...');
print('Finalizado');
}
O print() escreve uma mensagem no terminal e pula para a próxima linha, assim como em outras linguagens.
Usando variáveis no print
Em Dart, usamos $variavel para colocar o valor dentro de uma string.
void main() {
String nome = 'Fulano';
int idade = 27;
print('Nome: $nome');
print('Idade: $idade');
}
É parecido com Python, quando usamos f-string e muito similar ao Shell Script.
Usando expressão dentro de string
Quando você quer usar uma expressão maior, use ${}.
void main() {
double preco = 150.0;
double desconto = 20.0;
print('Preço final: ${preco - desconto}');
}
Aqui não estamos apenas exibindo uma variável, mas calculando uma expressão!
print vs stdout.write
O print() pula linha automaticamente após exibir os dados. Já o stdout.write() escreve na mesma linha:
import 'dart:io';
void main() {
stdout.write('Digite seu nome: ');
}
O cursor fica na mesma linha esperando a entrada. Isso é muito usado antes de ler uma entrada do usuário.
Lendo dados do usuário
Para ler o que o usuário digita no terminal, podemos usar:
stdin.readLineSync()
Exemplo completo, já que precisa do import:
import 'dart:io';
void main() {
stdout.write('Digite seu nome: ');
String? nome = stdin.readLineSync();
print('Olá, $nome');
}
Tratando valor nulo
Uma forma simples de tratar null é usando ??.
import 'dart:io';
void main() {
stdout.write('Digite seu nome: ');
String nome = stdin.readLineSync() ?? 'Usuário';
print('Olá, $nome');
}
A linha: String nome = stdin.readLineSync() ?? 'Usuário'; significa algo como: se o usuário digitou algo, use o valor digitado, se não, use Usuário. Isso é útil quando uma informação pode receber um valor padrão.
Lendo número inteiro
Tudo que vem do terminal entra como texto, mas isso pode ser ruim quando o usuário precisar digitar algum valor numérico, como uma idade, esse valor acaba indo como String. Temos então que converter para int:
import 'dart:io';
void main() {
stdout.write('Digite sua idade: ');
String? entrada = stdin.readLineSync();
int idade = int.parse(entrada!);
print('Idade informada: $idade');
}
O ! informa ao Dart que a variável não é null, mas tenha cuidado, se entrada for null, o programa quebra.
Forma segura com tryParse
Um método melhor e mais seguro é com o int.tryParse().
import 'dart:io';
void main() {
stdout.write('Digite sua idade: ');
String entrada = stdin.readLineSync() ?? '';
int? idade = int.tryParse(entrada);
if (idade == null) {
print('Idade inválida');
return;
}
print('Idade informada: $idade');
}
Isso evita erro quando o usuário digita texto no lugar de número.
Lendo número decimal
Para números com casas decimais, use double.tryParse().
import 'dart:io';
void main() {
stdout.write('Digite o preço do produto: ');
String entrada = stdin.readLineSync() ?? '';
double? preco = double.tryParse(entrada);
if (preco == null) {
print('Preço inválido');
return;
}
print('Preço cadastrado: R\$ $preco');
}
Trabalhando com arquivos
Para manipular arquivos simples, podemos usar a classe File, ela também vem do import 'dart:io';.
import 'dart:io';
void main() {
final arquivo = File('logs.txt');
arquivo.writeAsStringSync('Sistema iniciado\n');
print('Arquivo criado com sucesso');
}
A linha arquivo.writeAsStringSync('Sistema iniciado\n'); escreve texto dentro do arquivo. O \n quebra linha. Se o arquivo não existir, ele será criado. Se o arquivo já existir, o conteúdo anterior será sobrescrito.
Adicionando conteúdo ao arquivo
Se você quiser adicionar conteúdo sem apagar o que já existe, use mode: FileMode.append.
import 'dart:io';
void main() {
final arquivo = File('logs.txt');
arquivo.writeAsStringSync(
'Usuário Fulano acessou o sistema\n',
mode: FileMode.append,
);
print('Log adicionado');
}
Lendo arquivo
Para ler o conteúdo de um arquivo, usamos o readAsStringSync().
import 'dart:io';
void main() {
final arquivo = File('logs.txt');
String conteudo = arquivo.readAsStringSync();
print(conteudo);
}
Verificando se o arquivo existe
Se você tentar ler um arquivo que não existe, o programa dá erro, então temos que verificar se ele existe antes:
import 'dart:io';
void main() {
final arquivo = File('logs.txt');
if (!arquivo.existsSync()) {
print('Arquivo não encontrado');
return;
}
String conteudo = arquivo.readAsStringSync();
print(conteudo);
}
A linha: arquivo.existsSync() verifica se o arquivo existe. Quando usamos o !, ele inverte o resultado. Então se o normal é verificar se existe, quando usamos !, ele vai verificar se não existe.
Com Sync e Sem Sync
Até agora vimos métodos como:
- readAsStringSync()
- writeAsStringSync()
- existsSync()
O Sync significa síncrono, ou seja, o programa espera a operação terminar para continuar. Para estudos e scripts CLI simples, isso é aceitável. Mas em aplicações maiores, servidores ou Flutter, é comum usar versões assíncronas, como em:
await arquivo.writeAsString('texto');
await arquivo.readAsString();
Isso será melhor estudado depois, junto com Future, async e await.