Skip to main content


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!




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.